Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <fcntl.h>
3 : : #include <errno.h>
4 : :
5 : : #include <linux/limits.h>
6 : :
7 : : #include <sys/types.h>
8 : : #include <sys/prctl.h>
9 : : #include <sys/mman.h>
10 : : #include <sys/stat.h>
11 : : #include <sys/socket.h>
12 : : #include <sys/un.h>
13 : : #include <stdlib.h>
14 : :
15 : : #include "crtools.h"
16 : :
17 : : #include "files.h"
18 : : #include "files-reg.h"
19 : : #include "image.h"
20 : : #include "list.h"
21 : : #include "util.h"
22 : : #include "util-net.h"
23 : : #include "lock.h"
24 : : #include "sockets.h"
25 : : #include "pstree.h"
26 : : #include "tty.h"
27 : :
28 : : #include "protobuf.h"
29 : : #include "protobuf/fs.pb-c.h"
30 : :
31 : : #define FDESC_HASH_SIZE 64
32 : : static struct list_head file_desc_hash[FDESC_HASH_SIZE];
33 : :
34 : 380 : int prepare_shared_fdinfo(void)
35 : : {
36 : : int i;
37 : :
38 [ + + ]: 24700 : for (i = 0; i < FDESC_HASH_SIZE; i++)
39 : 24320 : INIT_LIST_HEAD(&file_desc_hash[i]);
40 : :
41 : 380 : return 0;
42 : : }
43 : :
44 : 19751 : void file_desc_add(struct file_desc *d, u32 id, struct file_desc_ops *ops)
45 : : {
46 : 19751 : d->id = id;
47 : 19751 : d->ops = ops;
48 : 19751 : INIT_LIST_HEAD(&d->fd_info_head);
49 : :
50 : 19751 : list_add_tail(&d->hash, &file_desc_hash[id % FDESC_HASH_SIZE]);
51 : 19751 : }
52 : :
53 : 12365 : struct file_desc *find_file_desc_raw(int type, u32 id)
54 : : {
55 : : struct file_desc *d;
56 : : struct list_head *chain;
57 : :
58 : 12365 : chain = &file_desc_hash[id % FDESC_HASH_SIZE];
59 [ + - ]: 26407 : list_for_each_entry(d, chain, hash)
60 [ + + ][ + + ]: 14042 : if (d->ops->type == type && d->id == id)
61 : : return d;
62 : :
63 : : return NULL;
64 : : }
65 : :
66 : : static inline struct file_desc *find_file_desc(FdinfoEntry *fe)
67 : : {
68 : 5898 : return find_file_desc_raw(fe->type, fe->id);
69 : : }
70 : :
71 : 5348 : struct fdinfo_list_entry *file_master(struct file_desc *d)
72 : : {
73 [ - + ]: 5348 : if (list_empty(&d->fd_info_head)) {
74 : 0 : pr_err("Empty list on file desc id %#x\n", d->id);
75 : 0 : BUG();
76 : : }
77 : :
78 : 5348 : return list_first_entry(&d->fd_info_head,
79 : : struct fdinfo_list_entry, desc_list);
80 : : }
81 : :
82 : 355 : void show_saved_files(void)
83 : : {
84 : : int i;
85 : : struct file_desc *fd;
86 : :
87 : 355 : pr_info("File descs:\n");
88 [ + + ]: 23075 : for (i = 0; i < FDESC_HASH_SIZE; i++)
89 [ + + ]: 42445 : list_for_each_entry(fd, &file_desc_hash[i], hash) {
90 : : struct fdinfo_list_entry *le;
91 : :
92 : 19725 : pr_info(" `- type %d ID %#x\n", fd->ops->type, fd->id);
93 [ + + ]: 25623 : list_for_each_entry(le, &fd->fd_info_head, desc_list)
94 : 5898 : pr_info(" `- FD %d pid %d\n", le->fe->fd, le->pid);
95 : : }
96 : 355 : }
97 : :
98 : 7249 : int restore_fown(int fd, FownEntry *fown)
99 : : {
100 : : struct f_owner_ex owner;
101 : : uid_t uids[3];
102 : 7249 : pid_t pid = getpid();
103 : :
104 [ + + ]: 7249 : if (fown->signum) {
105 [ - + ]: 2 : if (fcntl(fd, F_SETSIG, fown->signum)) {
106 : 0 : pr_perror("%d: Can't set signal", pid);
107 : : return -1;
108 : : }
109 : : }
110 : :
111 : : /* May be untouched */
112 [ + + ]: 7249 : if (!fown->pid)
113 : : return 0;
114 : :
115 [ - + ]: 2 : if (getresuid(&uids[0], &uids[1], &uids[2])) {
116 : 0 : pr_perror("%d: Can't get current UIDs", pid);
117 : : return -1;
118 : : }
119 : :
120 [ - + ]: 2 : if (setresuid(fown->uid, fown->euid, uids[2])) {
121 : 0 : pr_perror("%d: Can't set UIDs", pid);
122 : : return -1;
123 : : }
124 : :
125 : 2 : owner.type = fown->pid_type;
126 : 2 : owner.pid = fown->pid;
127 : :
128 [ - + ]: 2 : if (fcntl(fd, F_SETOWN_EX, &owner)) {
129 : 0 : pr_perror("%d: Can't setup %d file owner pid",
130 : : pid, fd);
131 : : return -1;
132 : : }
133 : :
134 [ - + ]: 2 : if (setresuid(uids[0], uids[1], uids[2])) {
135 : 7249 : pr_perror("%d: Can't revert UIDs back", pid);
136 : : return -1;
137 : : }
138 : :
139 : : return 0;
140 : : }
141 : :
142 : 196 : int rst_file_params(int fd, FownEntry *fown, int flags)
143 : : {
144 [ + - ]: 196 : if (set_fd_flags(fd, flags) < 0)
145 : : return -1;
146 [ + - ]: 196 : if (restore_fown(fd, fown) < 0)
147 : : return -1;
148 : 196 : return 0;
149 : : }
150 : :
151 : : static struct list_head *select_ps_list(struct file_desc *desc, struct rst_info *ri)
152 : : {
153 [ + + ]: 5898 : if (desc->ops->select_ps_list)
154 : 41 : return desc->ops->select_ps_list(desc, ri);
155 : : else
156 : 5857 : return &ri->fds;
157 : : }
158 : :
159 : 5898 : static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info)
160 : : {
161 : : struct fdinfo_list_entry *le, *new_le;
162 : : struct file_desc *fdesc;
163 : :
164 : 5898 : pr_info("Collect fdinfo pid=%d fd=%d id=0x%16x\n",
165 : : pid, e->fd, e->id);
166 : :
167 : 5898 : new_le = shmalloc(sizeof(*new_le));
168 [ + - ]: 5898 : if (!new_le)
169 : : return -1;
170 : :
171 : 5898 : futex_init(&new_le->real_pid);
172 : 5898 : new_le->pid = pid;
173 : 5898 : new_le->fe = e;
174 : :
175 : 17694 : fdesc = find_file_desc(e);
176 [ - + ]: 5898 : if (fdesc == NULL) {
177 : 0 : pr_err("No file for fd %d id %d\n", e->fd, e->id);
178 : 0 : return -1;
179 : : }
180 : :
181 [ + + ]: 14681 : list_for_each_entry(le, &fdesc->fd_info_head, desc_list) {
182 [ + + ]: 10889 : if (le->pid > new_le->pid)
183 : : break;
184 : : }
185 : :
186 : 5898 : list_add_tail(&new_le->desc_list, &le->desc_list);
187 : 5898 : new_le->desc = fdesc;
188 : 5898 : list_add_tail(&new_le->ps_list, select_ps_list(fdesc, rst_info));
189 : :
190 : 5898 : return 0;
191 : : }
192 : :
193 : 10 : int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id)
194 : : {
195 : : FdinfoEntry *e;
196 : :
197 [ + - ]: 10 : if (!ctl_tty_id)
198 : : return 0;
199 : :
200 : 10 : pr_info("Requesting for ctl tty %#x into service fd\n", ctl_tty_id);
201 : :
202 [ - + ]: 10 : e = xmalloc(sizeof(*e));
203 [ + - ]: 10 : if (!e)
204 : : return -1;
205 : :
206 : 10 : fdinfo_entry__init(e);
207 : :
208 : 10 : e->id = ctl_tty_id;
209 : 10 : e->fd = get_service_fd(CTL_TTY_OFF);
210 : 10 : e->type = FD_TYPES__TTY;
211 : :
212 [ - + ]: 10 : if (collect_fd(pid, e, rst_info)) {
213 [ # # ]: 10 : xfree(e);
214 : : return -1;
215 : : }
216 : :
217 : : return 0;
218 : : }
219 : :
220 : 1459 : int prepare_fd_pid(int pid, struct rst_info *rst_info)
221 : : {
222 : 1459 : int fdinfo_fd, ret = 0;
223 : :
224 : 1459 : INIT_LIST_HEAD(&rst_info->fds);
225 : 1459 : INIT_LIST_HEAD(&rst_info->eventpoll);
226 : 1459 : INIT_LIST_HEAD(&rst_info->tty_slaves);
227 : :
228 : 1459 : fdinfo_fd = open_image_ro(CR_FD_FDINFO, pid);
229 [ + + ]: 1459 : if (fdinfo_fd < 0) {
230 [ - + ]: 33 : if (errno == ENOENT)
231 : : return 0;
232 : : else
233 : 0 : return -1;
234 : : }
235 : :
236 : : while (1) {
237 : : FdinfoEntry *e;
238 : :
239 : 7314 : ret = pb_read_one_eof(fdinfo_fd, &e, PB_FDINFO);
240 [ + + ]: 7314 : if (ret <= 0)
241 : : break;
242 : :
243 : 5888 : ret = collect_fd(pid, e, rst_info);
244 [ - + ]: 5888 : if (ret < 0) {
245 : 0 : fdinfo_entry__free_unpacked(e, NULL);
246 : : break;
247 : : }
248 : 5888 : }
249 : :
250 : 1426 : close(fdinfo_fd);
251 : 1459 : return ret;
252 : : }
253 : :
254 : : #define SETFL_MASK (O_APPEND | O_ASYNC | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
255 : 196 : int set_fd_flags(int fd, int flags)
256 : : {
257 : : int ret;
258 : :
259 : 196 : ret = fcntl(fd, F_GETFL, 0);
260 [ + - ]: 196 : if (ret < 0)
261 : : goto err;
262 : :
263 : 196 : flags = (SETFL_MASK & flags) | (ret & ~SETFL_MASK);
264 : :
265 : 196 : ret = fcntl(fd, F_SETFL, flags);
266 [ - + ]: 196 : if (ret < 0)
267 : : goto err;
268 : : return 0;
269 : :
270 : : err:
271 : 0 : pr_perror("fcntl call on fd %d (flags %x) failed", fd, flags);
272 : 196 : return -1;
273 : : }
274 : :
275 : 1052 : static void transport_name_gen(struct sockaddr_un *addr, int *len,
276 : : int pid, int fd)
277 : : {
278 : 1052 : addr->sun_family = AF_UNIX;
279 : 1052 : snprintf(addr->sun_path, UNIX_PATH_MAX, "x/crtools-fd-%d-%d", pid, fd);
280 : 1052 : *len = SUN_LEN(addr);
281 : 1052 : *addr->sun_path = '\0';
282 : 1052 : }
283 : :
284 : : static int should_open_transport(FdinfoEntry *fe, struct file_desc *fd)
285 : : {
286 [ + + ]: 820 : if (fd->ops->want_transport)
287 : 202 : return fd->ops->want_transport(fe, fd);
288 : : else
289 : : return 0;
290 : : }
291 : :
292 : 1512 : static int open_transport_fd(int pid, struct fdinfo_list_entry *fle)
293 : : {
294 : : struct fdinfo_list_entry *flem;
295 : : struct sockaddr_un saddr;
296 : : int sock;
297 : : int ret, sun_len;
298 : :
299 : 1512 : flem = file_master(fle->desc);
300 : :
301 [ + + ]: 1512 : if (flem->pid == pid) {
302 [ + + ]: 1075 : if (flem->fe->fd != fle->fe->fd)
303 : : /* dup-ed file. Will be opened in the open_fd */
304 : : return 0;
305 : :
306 [ + + ]: 820 : if (!should_open_transport(fle->fe, fle->desc))
307 : : /* pure master file */
308 : : return 0;
309 : :
310 : : /*
311 : : * some master file, that wants a transport, e.g.
312 : : * a pipe or unix socket pair 'slave' end
313 : : */
314 : : }
315 : :
316 : 526 : transport_name_gen(&saddr, &sun_len, getpid(), fle->fe->fd);
317 : :
318 : 526 : pr_info("\t\tCreate transport fd %s\n", saddr.sun_path + 1);
319 : :
320 : :
321 : 526 : sock = socket(PF_UNIX, SOCK_DGRAM, 0);
322 [ - + ]: 526 : if (sock < 0) {
323 : 0 : pr_perror("Can't create socket");
324 : : return -1;
325 : : }
326 : 526 : ret = bind(sock, &saddr, sun_len);
327 [ - + ]: 526 : if (ret < 0) {
328 : 0 : pr_perror("Can't bind unix socket %s", saddr.sun_path + 1);
329 : : return -1;
330 : : }
331 : :
332 : 526 : ret = reopen_fd_as(fle->fe->fd, sock);
333 [ + - ]: 526 : if (ret < 0)
334 : : return -1;
335 : :
336 : 526 : pr_info("\t\tWake up fdinfo pid=%d fd=%d\n", fle->pid, fle->fe->fd);
337 : 1512 : futex_set_and_wake(&fle->real_pid, getpid());
338 : :
339 : : return 0;
340 : : }
341 : :
342 : 526 : int send_fd_to_peer(int fd, struct fdinfo_list_entry *fle, int sock)
343 : : {
344 : : struct sockaddr_un saddr;
345 : : int len;
346 : :
347 : 526 : pr_info("\t\tWait fdinfo pid=%d fd=%d\n", fle->pid, fle->fe->fd);
348 : 526 : futex_wait_while(&fle->real_pid, 0);
349 : 526 : transport_name_gen(&saddr, &len,
350 : 1052 : futex_get(&fle->real_pid), fle->fe->fd);
351 : 526 : pr_info("\t\tSend fd %d to %s\n", fd, saddr.sun_path + 1);
352 : 526 : return send_fd(sock, &saddr, len, fd);
353 : : }
354 : :
355 : 1075 : static int send_fd_to_self(int fd, struct fdinfo_list_entry *fle, int *sock)
356 : : {
357 : 1075 : int dfd = fle->fe->fd;
358 : :
359 [ + + ]: 1075 : if (fd == dfd)
360 : : return 0;
361 : :
362 : 255 : pr_info("\t\t\tGoing to dup %d into %d\n", fd, dfd);
363 [ + - ]: 255 : if (move_img_fd(sock, dfd))
364 : : return -1;
365 : :
366 [ - + ]: 255 : if (dup2(fd, dfd) != dfd) {
367 : 0 : pr_perror("Can't dup local fd %d -> %d", fd, dfd);
368 : : return -1;
369 : : }
370 : :
371 : 1075 : fcntl(dfd, F_SETFD, fle->fe->flags);
372 : : return 0;
373 : : }
374 : :
375 : 1512 : static int post_open_fd(int pid, struct fdinfo_list_entry *fle)
376 : : {
377 : 1512 : struct file_desc *d = fle->desc;
378 : :
379 [ + + ]: 1512 : if (!d->ops->post_open)
380 : : return 0;
381 : :
382 [ + + ]: 123 : if (is_service_fd(fle->fe->fd, CTL_TTY_OFF))
383 : 7 : return d->ops->post_open(d, fle->fe->fd);
384 : :
385 [ + - ]: 116 : if (fle != file_master(d))
386 : : return 0;
387 : :
388 : 1512 : return d->ops->post_open(d, fle->fe->fd);
389 : : }
390 : :
391 : :
392 : 820 : static int serve_out_fd(int pid, int fd, struct file_desc *d)
393 : : {
394 : : int sock, ret;
395 : : struct fdinfo_list_entry *fle;
396 : :
397 : 820 : sock = socket(PF_UNIX, SOCK_DGRAM, 0);
398 [ - + ]: 820 : if (sock < 0) {
399 : 0 : pr_perror("Can't create socket");
400 : : return -1;
401 : : }
402 : :
403 : 820 : pr_info("\t\tCreate fd for %d\n", fd);
404 : :
405 [ + + ]: 2332 : list_for_each_entry(fle, &d->fd_info_head, desc_list) {
406 [ + + ]: 1512 : if (pid == fle->pid)
407 : 1075 : ret = send_fd_to_self(fd, fle, &sock);
408 : : else
409 : 437 : ret = send_fd_to_peer(fd, fle, sock);
410 : :
411 [ - + ]: 1512 : if (ret) {
412 : 0 : pr_err("Can't sent fd %d to %d\n", fd, fle->pid);
413 : : return -1;
414 : : }
415 : : }
416 : :
417 : 820 : close(sock);
418 : : return 0;
419 : : }
420 : :
421 : 1512 : static int open_fd(int pid, struct fdinfo_list_entry *fle)
422 : : {
423 : 1512 : struct file_desc *d = fle->desc;
424 : : int new_fd;
425 : :
426 [ + + ]: 1512 : if (fle != file_master(d))
427 : : return 0;
428 : :
429 : 820 : new_fd = d->ops->open(d);
430 [ + - ]: 820 : if (new_fd < 0)
431 : : return -1;
432 : :
433 [ + - ]: 820 : if (reopen_fd_as(fle->fe->fd, new_fd))
434 : : return -1;
435 : :
436 : 820 : fcntl(fle->fe->fd, F_SETFD, fle->fe->flags);
437 : :
438 : 1512 : return serve_out_fd(pid, fle->fe->fd, d);
439 : : }
440 : :
441 : 1512 : static int receive_fd(int pid, struct fdinfo_list_entry *fle)
442 : : {
443 : : int tmp;
444 : : struct fdinfo_list_entry *flem;
445 : :
446 : 1512 : flem = file_master(fle->desc);
447 [ + + ]: 1512 : if (flem->pid == pid)
448 : : return 0;
449 : :
450 : 437 : pr_info("\tReceive fd for %d\n", fle->fe->fd);
451 : :
452 : 437 : tmp = recv_fd(fle->fe->fd);
453 [ - + ]: 437 : if (tmp < 0) {
454 : 0 : pr_err("Can't get fd %d\n", tmp);
455 : 0 : return -1;
456 : : }
457 : 437 : close(fle->fe->fd);
458 : :
459 [ + - ]: 437 : if (reopen_fd_as(fle->fe->fd, tmp) < 0)
460 : : return -1;
461 : :
462 : 437 : fcntl(tmp, F_SETFD, fle->fe->flags);
463 : 1512 : return 0;
464 : : }
465 : :
466 : : struct fd_open_state {
467 : : char *name;
468 : : int (*cb)(int, struct fdinfo_list_entry *);
469 : : };
470 : :
471 : : static struct fd_open_state states[] = {
472 : : { "prepare", open_transport_fd, },
473 : : { "create", open_fd, },
474 : : { "receive", receive_fd, },
475 : : { "post_create", post_open_fd, },
476 : : };
477 : :
478 : 6048 : static int open_fdinfo(int pid, struct fdinfo_list_entry *fle, int state)
479 : : {
480 : 6048 : pr_info("\tRestoring fd %d (state -> %s)\n",
481 : : fle->fe->fd, states[state].name);
482 : 6048 : return states[state].cb(pid, fle);
483 : : }
484 : :
485 : 4188 : static int open_fdinfos(int pid, struct list_head *list, int state)
486 : : {
487 : 4188 : int ret = 0;
488 : : struct fdinfo_list_entry *fle;
489 : :
490 [ + + ]: 10236 : list_for_each_entry(fle, list, ps_list) {
491 : 6048 : ret = open_fdinfo(pid, fle, state);
492 [ + - ]: 6048 : if (ret)
493 : : break;
494 : : }
495 : :
496 : 4188 : return ret;
497 : : }
498 : :
499 : 349 : static int close_old_fds(struct pstree_item *me)
500 : : {
501 : : DIR *dir;
502 : : struct dirent *de;
503 : : int fd, ret;
504 : :
505 [ - + ][ + - ]: 349 : dir = opendir_proc(getpid(), "fd");
[ - + ]
506 [ + - ]: 349 : if (dir == NULL)
507 : : return -1;
508 : :
509 [ + + ]: 4537 : while ((de = readdir(dir))) {
510 [ + + ]: 4188 : if (dir_dots(de))
511 : 698 : continue;
512 : :
513 : 3490 : ret = sscanf(de->d_name, "%d", &fd);
514 [ - + ]: 3490 : if (ret != 1) {
515 : 0 : pr_err("Can't parse %s\n", de->d_name);
516 : : return -1;
517 : : }
518 : :
519 [ + + ][ + + ]: 3490 : if ((!is_any_service_fd(fd)) && (dirfd(dir) != fd))
520 : 4188 : close_safe(&fd);
521 : : }
522 : :
523 : 349 : closedir(dir);
524 : 349 : close_pid_proc();
525 : :
526 : : return 0;
527 : : }
528 : :
529 : 349 : int prepare_fds(struct pstree_item *me)
530 : : {
531 : : u32 ret;
532 : : int state;
533 : :
534 : 349 : ret = close_old_fds(me);
535 [ + - ]: 349 : if (ret)
536 : : goto err;
537 : :
538 : 349 : pr_info("Opening fdinfo-s\n");
539 : :
540 [ + + ]: 1745 : for (state = 0; state < ARRAY_SIZE(states); state++) {
541 : 1396 : ret = open_fdinfos(me->pid.virt, &me->rst->fds, state);
542 [ + - ]: 1396 : if (ret)
543 : : break;
544 : :
545 : : /*
546 : : * Now handle TTYs. Slaves are delayed to be sure masters
547 : : * are already opened.
548 : : */
549 : 1396 : ret = open_fdinfos(me->pid.virt, &me->rst->tty_slaves, state);
550 [ + - ]: 1396 : if (ret)
551 : : break;
552 : :
553 : : /*
554 : : * The eventpoll descriptors require all the other ones
555 : : * to be already restored, thus we store them in a separate
556 : : * list and restore at the very end.
557 : : */
558 : 1396 : ret = open_fdinfos(me->pid.virt, &me->rst->eventpoll, state);
559 [ + - ]: 1396 : if (ret)
560 : : break;
561 : : }
562 : :
563 : : err:
564 : 349 : tty_fini_fds();
565 : 349 : return ret;
566 : : }
567 : :
568 : 349 : int prepare_fs(int pid)
569 : : {
570 : 349 : int ifd, cwd, ret = -1;
571 : : FsEntry *fe;
572 : :
573 : 349 : ifd = open_image_ro(CR_FD_FS, pid);
574 [ + - ]: 349 : if (ifd < 0)
575 : : return -1;
576 : :
577 [ - + ]: 349 : if (pb_read_one(ifd, &fe, PB_FS) < 0) {
578 : 0 : close_safe(&ifd);
579 : : return -1;
580 : : }
581 : :
582 : 349 : cwd = open_reg_by_id(fe->cwd_id);
583 [ - + ]: 349 : if (cwd < 0) {
584 : 0 : close_safe(&ifd);
585 : 0 : goto err;
586 : : }
587 : :
588 [ - + ]: 349 : if (fchdir(cwd) < 0) {
589 : 0 : pr_perror("Can't change root");
590 : 0 : goto close;
591 : : }
592 : :
593 : : /*
594 : : * FIXME: restore task's root. Don't want to do it now, since
595 : : * it's not yet clean how we're going to resolve tasks' paths
596 : : * relative to the dumper/restorer and all this logic is likely
597 : : * to be hidden in a couple of calls (open_fe_fd is one od them)
598 : : * but for chroot there's no fchroot call, we have to chroot
599 : : * by path thus exposing this (yet unclean) logic here.
600 : : */
601 : :
602 : : ret = 0;
603 : : close:
604 : 349 : close_safe(&cwd);
605 : 349 : close_safe(&ifd);
606 : : err:
607 : 349 : fs_entry__free_unpacked(fe, NULL);
608 : : return ret;
609 : : }
610 : :
611 : 5724 : int get_filemap_fd(int pid, VmaEntry *vma_entry)
612 : : {
613 : 5724 : return open_reg_by_id(vma_entry->shmid);
614 : 12871 : }
|