Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <sys/types.h>
3 : : #include <sys/stat.h>
4 : : #include <fcntl.h>
5 : : #include <stdlib.h>
6 : : #include <sys/mman.h>
7 : :
8 : : #include "fdset.h"
9 : : #include "image.h"
10 : : #include "files.h"
11 : : #include "pipes.h"
12 : : #include "util-pie.h"
13 : :
14 : : #include "protobuf.h"
15 : : #include "protobuf/pipe.pb-c.h"
16 : : #include "protobuf/pipe-data.pb-c.h"
17 : :
18 : : /*
19 : : * The sequence of objects which should be restored:
20 : : * pipe -> files struct-s -> fd-s.
21 : : * pipe_entry describes pipe's file structs-s.
22 : : * A pipe doesn't have own properties, so it has no object.
23 : : */
24 : :
25 : : struct pipe_info {
26 : : PipeEntry *pe;
27 : : struct list_head pipe_list; /* All pipe_info with the same pipe_id
28 : : * This is pure circular list without head */
29 : : struct list_head list; /* list head for fdinfo_list_entry-s */
30 : : struct file_desc d;
31 : : unsigned int create : 1,
32 : : reopen : 1;
33 : : };
34 : :
35 : : static LIST_HEAD(pipes);
36 : :
37 : 346 : static void show_saved_pipe_fds(struct pipe_info *pi)
38 : : {
39 : : struct fdinfo_list_entry *fle;
40 : :
41 : 346 : pr_info(" `- ID %p %#xpn", pi, pi->pe->id);
42 [ + + ]: 1052 : list_for_each_entry(fle, &pi->d.fd_info_head, desc_list)
43 : 706 : pr_info(" `- FD %d pid %d\n", fle->fe->fd, fle->pid);
44 : 346 : }
45 : :
46 : 400 : static int pipe_data_read(int fd, struct pipe_data_rst *r)
47 : : {
48 : 200 : unsigned long bytes = r->pde->bytes;
49 : :
50 [ + + ]: 200 : if (!bytes)
51 : : return 0;
52 : :
53 : : /*
54 : : * We potentially allocate more memory than required for data,
55 : : * but this is OK. Look at restore_pipe_data -- it vmsplice-s
56 : : * this into the kernel with F_GIFT flag (since some time it
57 : : * works on non-aligned data), thus just giving this page to
58 : : * pipe buffer. And since kernel allocates pipe buffers in pages
59 : : * anyway we don't increase memory consumption :)
60 : : */
61 : :
62 : 26 : r->data = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
63 : : MAP_SHARED | MAP_ANON, 0, 0);
64 [ - + ]: 26 : if (r->data == MAP_FAILED) {
65 : 0 : pr_perror("Can't map mem for pipe buffers");
66 : : return -1;
67 : : }
68 : :
69 : 26 : return read_img_buf(fd, r->data, bytes);
70 : : }
71 : :
72 : 710 : int collect_pipe_data(int img_type, struct pipe_data_rst **hash)
73 : : {
74 : : int fd, ret;
75 : 200 : struct pipe_data_rst *r = NULL;
76 : :
77 : 710 : fd = open_image(img_type, O_RSTR);
78 [ + - ]: 710 : if (fd < 0)
79 : : return -1;
80 : :
81 : : while (1) {
82 : : ret = -1;
83 [ - + ]: 910 : r = xmalloc(sizeof(*r));
84 [ + - ]: 910 : if (!r)
85 : : break;
86 : :
87 : 910 : ret = pb_read_one_eof(fd, &r->pde, PB_PIPE_DATA);
88 [ + + ]: 910 : if (ret <= 0)
89 : : break;
90 : :
91 : 200 : ret = pipe_data_read(fd, r);
92 [ + - ]: 200 : if (ret < 0)
93 : : break;
94 : :
95 : 200 : ret = r->pde->pipe_id & PIPE_DATA_HASH_MASK;
96 : 200 : r->next = hash[ret];
97 : 200 : hash[ret] = r;
98 : :
99 : 200 : pr_info("Collected pipe data for %#x (chain %u)\n",
100 : : r->pde->pipe_id, ret);
101 : 200 : }
102 : :
103 [ + - ][ - + ]: 710 : if (r && r->pde)
104 : 0 : pipe_data_entry__free_unpacked(r->pde, NULL);
105 [ + - ]: 710 : xfree(r);
106 : :
107 : 710 : close(fd);
108 : 710 : return ret;
109 : : }
110 : :
111 : : /* Choose who will restore a pipe. */
112 : 355 : void mark_pipe_master(void)
113 : : {
114 : 355 : LIST_HEAD(head);
115 : :
116 : 355 : pr_info("Pipes:\n");
117 : :
118 : : while (1) {
119 : 162 : struct fdinfo_list_entry *fle;
120 : : struct pipe_info *pi, *pic, *p;
121 : : struct pipe_info *pr = NULL, *pw = NULL;
122 : :
123 [ + + ]: 539 : if (list_empty(&pipes))
124 : : break;
125 : :
126 : 184 : pi = list_first_entry(&pipes, struct pipe_info, list);
127 : 184 : list_move(&pi->list, &head);
128 : :
129 : 184 : pr_info(" `- PIPE ID %#x\n", pi->pe->pipe_id);
130 : 184 : show_saved_pipe_fds(pi);
131 : :
132 : 184 : fle = file_master(&pi->d);
133 : : p = pi;
134 : : if (!(pi->pe->flags & O_LARGEFILE)) {
135 [ + + ]: 184 : if (pi->pe->flags & O_WRONLY) {
136 : : if (pw == NULL)
137 : : pw = pi;
138 : : } else {
139 : : if (pr == NULL)
140 : : pr = pi;
141 : : }
142 : : }
143 : :
144 [ + + ]: 346 : list_for_each_entry(pic, &pi->pipe_list, pipe_list) {
145 : 162 : struct fdinfo_list_entry *f;
146 : :
147 : 162 : list_move(&pic->list, &head);
148 : 162 : f = file_master(&pic->d);
149 [ - + ]: 162 : if (fdinfo_rst_prio(f, fle)) {
150 : : p = pic;
151 : : fle = f;
152 : : }
153 : :
154 : : if (!(pic->pe->flags & O_LARGEFILE)) {
155 [ + + ]: 162 : if (pic->pe->flags & O_WRONLY) {
156 [ + + ]: 124 : if (pw == NULL)
157 : : pw = pic;
158 : : } else {
159 [ + + ]: 38 : if (pr == NULL)
160 : : pr = pic;
161 : : }
162 : : }
163 : :
164 : 162 : show_saved_pipe_fds(pic);
165 : : }
166 : 184 : p->create = 1;
167 [ + - ]: 184 : if (pr)
168 : 184 : pr->reopen = 0;
169 [ + + ]: 184 : if (pw)
170 : 158 : pw->reopen = 0;
171 : 184 : pr_info(" by %#x\n", p->pe->id);
172 : 184 : }
173 : :
174 : : list_splice(&head, &pipes);
175 : 355 : }
176 : :
177 : : static struct pipe_data_rst *pd_hash_pipes[PIPE_DATA_HASH_SIZE];
178 : :
179 : 90 : int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash)
180 : : {
181 : : int ret;
182 : : struct pipe_data_rst *pd;
183 : : struct iovec iov;
184 : :
185 [ + - ]: 90 : for (pd = hash[id & PIPE_DATA_HASH_MASK]; pd != NULL; pd = pd->next)
186 [ - + ]: 90 : if (pd->pde->pipe_id == id)
187 : : break;
188 : :
189 [ - + ]: 90 : if (!pd) { /* no data for this pipe */
190 : 0 : pr_info("No data for pipe %#x\n", id);
191 : 0 : return 0;
192 : : }
193 : :
194 [ + + ]: 90 : if (!pd->pde->bytes)
195 : : goto out;
196 : :
197 [ - + ]: 15 : if (!pd->data) {
198 : 0 : pr_err("Double data restore occurred on %#x\n", id);
199 : 0 : return -1;
200 : : }
201 : :
202 : 15 : iov.iov_base = pd->data;
203 : 15 : iov.iov_len = pd->pde->bytes;
204 : :
205 [ + + ]: 30 : while (iov.iov_len > 0) {
206 : 15 : ret = vmsplice(pfd, &iov, 1, SPLICE_F_GIFT | SPLICE_F_NONBLOCK);
207 [ - + ]: 15 : if (ret < 0) {
208 : 0 : pr_perror("%#x: Error splicing data", id);
209 : 0 : goto err;
210 : : }
211 : :
212 [ + - ][ - + ]: 15 : if (ret == 0 || ret > iov.iov_len /* sanity */) {
213 : 0 : pr_err("%#x: Wanted to restore %zu bytes, but got %d\n", id,
214 : : iov.iov_len, ret);
215 : : ret = -1;
216 : 0 : goto err;
217 : : }
218 : :
219 : 15 : iov.iov_base += ret;
220 : 15 : iov.iov_len -= ret;
221 : : }
222 : :
223 : : /*
224 : : * 3 reasons for killing the buffer from our address space:
225 : : *
226 : : * 1. We gifted the pages to the kernel to optimize memory usage, thus
227 : : * accidental memory corruption can change the pipe buffer.
228 : : * 2. This will make the vmas restoration a bit faster due to less self
229 : : * mappings to be unmapped.
230 : : * 3. We can catch bugs with double pipe data restore.
231 : : */
232 : :
233 : 15 : munmap(pd->data, pd->pde->bytes);
234 : 15 : pd->data = NULL;
235 : : out:
236 : : ret = 0;
237 [ + - ]: 90 : if (pd->pde->has_size) {
238 : 90 : pr_info("Restoring size %#x for %#x\n",
239 : : pd->pde->size, pd->pde->pipe_id);
240 : 90 : ret = fcntl(pfd, F_SETPIPE_SZ, pd->pde->size);
241 [ - + ]: 90 : if (ret < 0)
242 : 0 : pr_perror("Can't restore pipe size");
243 : : else
244 : : ret = 0;
245 : : }
246 : : err:
247 : 90 : return ret;
248 : : }
249 : :
250 : 4 : static int reopen_pipe(int fd, int flags)
251 : : {
252 : : int ret;
253 : : char path[PSFDS];
254 : :
255 : : sprintf(path, "/proc/self/fd/%d", fd);
256 : : ret = open(path, flags);
257 [ - + ]: 4 : if (ret < 0)
258 : 0 : pr_perror("Unable to reopen the pipe %s", path);
259 : 4 : close(fd);
260 : :
261 : 4 : return ret;
262 : : }
263 : :
264 : 64 : static int recv_pipe_fd(struct pipe_info *pi)
265 : : {
266 : : struct fdinfo_list_entry *fle;
267 : : int tmp, fd;
268 : :
269 : 64 : fle = file_master(&pi->d);
270 : 64 : fd = fle->fe->fd;
271 : :
272 : 64 : pr_info("\tWaiting fd for %d\n", fd);
273 : :
274 : 64 : tmp = recv_fd(fd);
275 [ - + ]: 64 : if (tmp < 0) {
276 : 0 : pr_err("Can't get fd %d\n", tmp);
277 : 0 : return -1;
278 : : }
279 : 64 : close(fd);
280 : :
281 [ + + ]: 64 : if (pi->reopen)
282 : 4 : fd = reopen_pipe(tmp, pi->pe->flags);
283 : : else
284 : : fd = tmp;
285 [ + - ]: 64 : if (fd >= 0) {
286 [ - + ]: 64 : if (rst_file_params(fd, pi->pe->fown, pi->pe->flags)) {
287 : 0 : close(fd);
288 : 0 : return -1;
289 : : }
290 : : }
291 : :
292 : 64 : return fd;
293 : : }
294 : :
295 : 144 : static int open_pipe(struct file_desc *d)
296 : : {
297 : : struct pipe_info *pi, *p;
298 : : int ret, tmp;
299 : : int pfd[2];
300 : : int sock;
301 : :
302 : 144 : pi = container_of(d, struct pipe_info, d);
303 : :
304 : 144 : pr_info("\t\tCreating pipe pipe_id=%#x id=%#x\n", pi->pe->pipe_id, pi->pe->id);
305 : :
306 [ + + ]: 144 : if (!pi->create)
307 : 64 : return recv_pipe_fd(pi);
308 : :
309 [ - + ]: 80 : if (pipe(pfd) < 0) {
310 : 0 : pr_perror("Can't create pipe");
311 : 0 : return -1;
312 : : }
313 : :
314 : 80 : ret = restore_pipe_data(CR_FD_PIPES_DATA, pfd[1],
315 : 80 : pi->pe->pipe_id, pd_hash_pipes);
316 [ + - ]: 80 : if (ret)
317 : : return -1;
318 : :
319 : 80 : sock = socket(PF_UNIX, SOCK_DGRAM, 0);
320 [ - + ]: 80 : if (sock < 0) {
321 : 0 : pr_perror("Can't create socket");
322 : 0 : return -1;
323 : : }
324 : :
325 [ + + ]: 152 : list_for_each_entry(p, &pi->pipe_list, pipe_list) {
326 : : struct fdinfo_list_entry *fle;
327 : : int fd;
328 : :
329 : 72 : fle = file_master(&p->d);
330 : 72 : fd = pfd[p->pe->flags & O_WRONLY];
331 : :
332 [ - + ]: 72 : if (send_fd_to_peer(fd, fle, sock)) {
333 : 0 : pr_perror("Can't send file descriptor");
334 : 0 : return -1;
335 : : }
336 : : }
337 : :
338 : 80 : close(sock);
339 : :
340 : 80 : close(pfd[!(pi->pe->flags & O_WRONLY)]);
341 : 80 : tmp = pfd[pi->pe->flags & O_WRONLY];
342 : :
343 [ - + ]: 80 : if (pi->reopen)
344 : 0 : tmp = reopen_pipe(tmp, pi->pe->flags);
345 : :
346 [ + - ]: 80 : if (tmp >= 0)
347 [ + - ]: 80 : if (rst_file_params(tmp, pi->pe->fown, pi->pe->flags))
348 : : return -1;
349 : :
350 : 80 : return tmp;
351 : : }
352 : :
353 : 144 : static int want_transport(FdinfoEntry *fe, struct file_desc *d)
354 : : {
355 : : struct pipe_info *pi;
356 : :
357 : : pi = container_of(d, struct pipe_info, d);
358 : 144 : return !pi->create;
359 : : }
360 : :
361 : : static struct file_desc_ops pipe_desc_ops = {
362 : : .type = FD_TYPES__PIPE,
363 : : .open = open_pipe,
364 : : .want_transport = want_transport,
365 : : };
366 : :
367 : 346 : static int collect_one_pipe(void *o, ProtobufCMessage *base)
368 : : {
369 : : struct pipe_info *pi = o, *tmp;
370 : :
371 : 346 : pi->pe = pb_msg(base, PipeEntry);
372 : :
373 : 346 : pi->create = 0;
374 : 346 : pi->reopen = 1;
375 : 346 : pr_info("Collected pipe entry ID %#x PIPE ID %#x\n",
376 : : pi->pe->id, pi->pe->pipe_id);
377 : :
378 [ + + ]: 1058 : list_for_each_entry(tmp, &pipes, list)
379 [ + + ]: 874 : if (pi->pe->pipe_id == tmp->pe->pipe_id)
380 : : break;
381 : :
382 [ + + ]: 346 : if (&tmp->list == &pipes)
383 : 184 : INIT_LIST_HEAD(&pi->pipe_list);
384 : : else
385 : 162 : list_add(&pi->pipe_list, &tmp->pipe_list);
386 : :
387 : 346 : list_add_tail(&pi->list, &pipes);
388 : 346 : return file_desc_add(&pi->d, pi->pe->id, &pipe_desc_ops);
389 : :
390 : : }
391 : :
392 : : struct collect_image_info pipe_cinfo = {
393 : : .fd_type = CR_FD_PIPES,
394 : : .pb_type = PB_PIPE,
395 : : .priv_size = sizeof(struct pipe_info),
396 : : .collect = collect_one_pipe,
397 : : };
398 : :
399 : 355 : int collect_pipes(void)
400 : : {
401 : 355 : return collect_pipe_data(CR_FD_PIPES_DATA, pd_hash_pipes);
402 : : }
403 : :
404 : 358 : int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms *p)
405 : : {
406 : : int img;
407 : : int pipe_size, i, bytes;
408 : : int steal_pipe[2];
409 : : int ret = -1;
410 : 358 : PipeDataEntry pde = PIPE_DATA_ENTRY__INIT;
411 : :
412 [ + + ]: 358 : if (p->flags & O_WRONLY)
413 : : return 0;
414 : :
415 : : /* Maybe we've dumped it already */
416 [ + + ]: 382 : for (i = 0; i < pd->nr; i++) {
417 [ + + ]: 186 : if (pd->ids[i] == pipe_id(p))
418 : : return 0;
419 : : }
420 : :
421 : 196 : pr_info("Dumping data from pipe %#x fd %d\n", pipe_id(p), lfd);
422 : :
423 [ - + ]: 196 : if (pd->nr >= NR_PIPES_WITH_DATA) {
424 : 0 : pr_err("OOM storing pipe\n");
425 : 0 : return -1;
426 : : }
427 : :
428 : 196 : img = fdset_fd(glob_fdset, pd->img_type);
429 : 392 : pd->ids[pd->nr++] = pipe_id(p);
430 : :
431 : 196 : pipe_size = fcntl(lfd, F_GETPIPE_SZ);
432 [ - + ]: 196 : if (pipe_size < 0) {
433 : 0 : pr_err("Can't obtain piped data size\n");
434 : 0 : goto err;
435 : : }
436 : :
437 [ - + ]: 196 : if (pipe(steal_pipe) < 0) {
438 : 0 : pr_perror("Can't create pipe for stealing data");
439 : 0 : goto err;
440 : : }
441 : :
442 : 196 : bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK);
443 [ + + ]: 196 : if (bytes < 0) {
444 [ - + ]: 133 : if (errno != EAGAIN) {
445 : 0 : pr_perror("Can't pick pipe data");
446 : 0 : goto err_close;
447 : : }
448 : :
449 : : bytes = 0;
450 : : }
451 : :
452 : 196 : pde.pipe_id = pipe_id(p);
453 : 196 : pde.bytes = bytes;
454 : 196 : pde.has_size = true;
455 : 196 : pde.size = pipe_size;
456 : :
457 [ + - ]: 196 : if (pb_write_one(img, &pde, PB_PIPE_DATA))
458 : : goto err_close;
459 : :
460 [ + + ]: 196 : if (bytes) {
461 : : int wrote;
462 : :
463 : 33 : wrote = splice(steal_pipe[0], NULL, img, NULL, bytes, 0);
464 [ - + ]: 33 : if (wrote < 0) {
465 : 0 : pr_perror("Can't push pipe data");
466 : 0 : goto err_close;
467 [ - + ]: 33 : } else if (wrote != bytes) {
468 : 0 : pr_err("%#x: Wanted to write %d bytes, but wrote %d\n",
469 : : pipe_id(p), bytes, wrote);
470 : 0 : goto err_close;
471 : : }
472 : : }
473 : :
474 : : ret = 0;
475 : :
476 : : err_close:
477 : 196 : close(steal_pipe[0]);
478 : 196 : close(steal_pipe[1]);
479 : : err:
480 : 196 : return ret;
481 : : }
482 : :
483 : : static struct pipe_data_dump pd_pipes = { .img_type = CR_FD_PIPES_DATA, };
484 : :
485 : 330 : static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p)
486 : : {
487 : 330 : PipeEntry pe = PIPE_ENTRY__INIT;
488 : :
489 : 330 : pr_info("Dumping pipe %d with id %#x pipe_id %#x\n",
490 : : lfd, id, pipe_id(p));
491 : :
492 [ - + ]: 330 : if (p->flags & O_DIRECT) {
493 : 0 : pr_err("The packetized mode for pipes is not supported yet\n");
494 : 0 : return -1;
495 : : }
496 : :
497 : 330 : pe.id = id;
498 : 330 : pe.pipe_id = pipe_id(p);
499 : 330 : pe.flags = p->flags;
500 : 330 : pe.fown = (FownEntry *)&p->fown;
501 : :
502 [ + - ]: 330 : if (pb_write_one(fdset_fd(glob_fdset, CR_FD_PIPES), &pe, PB_PIPE))
503 : : return -1;
504 : :
505 : 330 : return dump_one_pipe_data(&pd_pipes, lfd, p);
506 : : }
507 : :
508 : : const struct fdtype_ops pipe_dump_ops = {
509 : : .type = FD_TYPES__PIPE,
510 : : .dump = dump_one_pipe,
511 : : };
|