1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <assert.h>
4 #include <elf.h>
5 #include <endian.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <link.h>
10 #include <linux/stddef.h>
11 #include <linux/io_uring.h>
12 #include <linux/swab.h>
13 #include <linux/coredump.h>
14 #include <linux/fs.h>
15 #include <poll.h>
16 #include <pthread.h>
17 #include <stdbool.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/epoll.h>
22 #include <sys/ioctl.h>
23 #include <sys/mman.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/syscall.h>
27 #include <sys/types.h>
28 #include <sys/un.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
31
32 #include "../filesystems/wrappers.h"
33 #include "coredump_notify_signal.h"
34
35 #include "coredump_test_helpers.h"
36
37 #if __ELF_NATIVE_CLASS == 64
38 #define COREDUMP_ELFCLASS ELFCLASS64
39 #else
40 #define COREDUMP_ELFCLASS ELFCLASS32
41 #endif
42
43 #ifndef SO_PEERPIDFD_THREAD
44 #define SO_PEERPIDFD_THREAD 87
45 #endif
46
do_nothing(void * arg)47 void *do_nothing(void *arg)
48 {
49 (void)arg;
50 while (1)
51 pause();
52
53 return NULL;
54 }
55
crashing_child(void)56 void crashing_child(void)
57 {
58 pthread_t thread;
59 int i;
60
61 for (i = 0; i < NUM_THREAD_SPAWN; ++i)
62 pthread_create(&thread, NULL, do_nothing, NULL);
63
64 /* crash on purpose */
65 i = *(volatile int *)NULL;
66 }
67
crashing_child_sparse(size_t size)68 void crashing_child_sparse(size_t size)
69 {
70 char *p;
71
72 /*
73 * Touch the first and the last page. This will cause the whole mapping
74 * to be dumped because it has been written to. Everything between
75 * those two pages is a hole though.
76 */
77 p = mmap(NULL, size, PROT_READ | PROT_WRITE,
78 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
79 if (p != MAP_FAILED) {
80 p[0] = 'x';
81 p[size - 1] = 'x';
82 }
83
84 /* crash on purpose */
85 *(volatile int *)NULL = 0;
86 }
87
88 /* Select @types through the caller's own /proc/self/coredump_filter. */
set_coredump_filter(__u64 types)89 static bool set_coredump_filter(__u64 types)
90 {
91 char buf[32];
92 int fd, len;
93 bool ok;
94
95 fd = open("/proc/self/coredump_filter", O_WRONLY | O_CLOEXEC);
96 if (fd < 0)
97 return false;
98
99 len = snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)types);
100 ok = write_nointr(fd, buf, len) == len;
101 close(fd);
102 return ok;
103 }
104
105 /*
106 * Map shared anonymous memory, touch it, tell the server where it is and
107 * crash. A @task_filter other than FILTER_TASK_INHERIT is selected first.
108 */
crashing_child_memory(__u64 task_filter,int fd_addr)109 void crashing_child_memory(__u64 task_filter, int fd_addr)
110 {
111 char *p;
112
113 if (task_filter != FILTER_TASK_INHERIT && !set_coredump_filter(task_filter))
114 _exit(EXIT_FAILURE);
115
116 p = mmap(NULL, MEMORY_MAPPING_SIZE, PROT_READ | PROT_WRITE,
117 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
118 if (p == MAP_FAILED)
119 _exit(EXIT_FAILURE);
120 p[0] = 'x';
121
122 if (write_nointr(fd_addr, &p, sizeof(p)) != sizeof(p))
123 _exit(EXIT_FAILURE);
124 close(fd_addr);
125
126 /* crash on purpose */
127 *(volatile int *)NULL = 0;
128 }
129
130 /* Sink a reassembled record stream is handed to, record by record. */
131 struct coredump_record_sink {
132 /* @len bytes of coredump data that belong at @offset. */
133 int (*data)(void *ctx, const void *buf, size_t len, __u64 offset);
134 /* @len zero bytes that belong at @offset. */
135 int (*zero)(void *ctx, __u64 offset, __u64 len);
136 void *ctx;
137 };
138
139 /* Read @len bytes off the socket and hand them to @sink, if there is one. */
recv_record_bytes(int fd_coredump,__u64 len,const struct coredump_record_sink * sink,__u64 offset)140 static ssize_t recv_record_bytes(int fd_coredump, __u64 len,
141 const struct coredump_record_sink *sink,
142 __u64 offset)
143 {
144 ssize_t received = 0;
145
146 while (len) {
147 char buffer[PAGE_SIZE];
148 size_t chunk = len < sizeof(buffer) ? len : sizeof(buffer);
149 ssize_t ret;
150
151 ret = recv(fd_coredump, buffer, chunk, MSG_WAITALL);
152 if (ret <= 0) {
153 fprintf(stderr, "%s: short read %zd: %m\n",
154 __func__, ret);
155 return -1;
156 }
157
158 if (sink && sink->data(sink->ctx, buffer, ret, offset + received))
159 return -1;
160
161 received += ret;
162 len -= ret;
163 }
164
165 return received;
166 }
167
168 /* Put the data where the records say it goes and leave the holes alone. */
file_sink_data(void * ctx,const void * buf,size_t len,__u64 offset)169 static int file_sink_data(void *ctx, const void *buf, size_t len, __u64 offset)
170 {
171 int fd = *(int *)ctx;
172
173 if (pwrite(fd, buf, len, offset) != (ssize_t)len) {
174 fprintf(stderr, "%s: pwrite failed: %m\n", __func__);
175 return -1;
176 }
177
178 return 0;
179 }
180
file_sink_zero(void * ctx,__u64 offset,__u64 len)181 static int file_sink_zero(void *ctx, __u64 offset, __u64 len)
182 {
183 /* Nothing has to be written for a hole. */
184 return 0;
185 }
186
187 /*
188 * Read a coredump strea and funnel it into @sink. Allow to pass in a
189 * @fd_peer_pidfd to simulate coredump truncation by killing it after having
190 * received a coredump record.
191 */
__recv_coredump_records(int fd_coredump,const struct coredump_record_sink * sink,off_t * coredump_size,bool * truncated,int fd_peer_pidfd)192 static ssize_t __recv_coredump_records(int fd_coredump,
193 const struct coredump_record_sink *sink,
194 off_t *coredump_size, bool *truncated,
195 int fd_peer_pidfd)
196 {
197 ssize_t received = 0;
198 off_t size = 0;
199 bool is_truncated = false;
200 bool ended = false;
201 char trailing;
202
203 while (!ended) {
204 struct coredump_record_header record = {};
205 size_t known_size;
206 ssize_t ret;
207
208 /* Peek the header size the way read_coredump_req() does. */
209 ret = recv(fd_coredump, &record, sizeof(record.size),
210 MSG_PEEK | MSG_WAITALL);
211 if (ret == 0) {
212 /* Nothing closed the stream, so the coredump was cut short. */
213 if (truncated) {
214 is_truncated = true;
215 break;
216 }
217 fprintf(stderr, "%s: stream ended without an end record\n",
218 __func__);
219 return -1;
220 }
221 if (ret != sizeof(record.size)) {
222 fprintf(stderr, "%s: short record peek %zd: %m\n",
223 __func__, ret);
224 return -1;
225 }
226
227 if (record.size < COREDUMP_RECORD_HEADER_SIZE_VER0) {
228 fprintf(stderr, "%s: header size %u below minimum %u\n",
229 __func__, record.size,
230 COREDUMP_RECORD_HEADER_SIZE_VER0);
231 return -1;
232 }
233
234 /* Consume as much of the header as we know about. */
235 known_size = record.size < sizeof(record) ? record.size : sizeof(record);
236 ret = recv(fd_coredump, &record, known_size, MSG_WAITALL);
237 if (ret != (ssize_t)known_size) {
238 fprintf(stderr, "%s: short record read %zd: %m\n",
239 __func__, ret);
240 return -1;
241 }
242 received += ret;
243
244 /*
245 * A flag changes what the record means, so refuse one we
246 * don't know rather than guess.
247 */
248 if (record.flags) {
249 fprintf(stderr, "%s: unknown header flags 0x%llx\n",
250 __func__, (unsigned long long)record.flags);
251 return -1;
252 }
253
254 /* Discard any part of the header we have no use for. */
255 ret = recv_record_bytes(fd_coredump, record.size - known_size,
256 NULL, 0);
257 if (ret < 0)
258 return -1;
259 received += ret;
260
261 /* Records are sent in order and they don't leave gaps. */
262 if (record.offset != (__u64)size) {
263 fprintf(stderr, "%s: record at %llu, expected %llu\n",
264 __func__, (unsigned long long)record.offset,
265 (unsigned long long)size);
266 return -1;
267 }
268
269 switch (record.type) {
270 case COREDUMP_RECORD_ZERO:
271 /* A hole. It comes with no data and needs none. */
272 if (sink->zero(sink->ctx, record.offset, record.len))
273 return -1;
274 break;
275 case COREDUMP_RECORD_DATA:
276 ret = recv_record_bytes(fd_coredump, record.len, sink,
277 record.offset);
278 if (ret < 0)
279 return -1;
280 received += ret;
281 if (fd_peer_pidfd >= 0) {
282 if (sys_pidfd_send_signal(fd_peer_pidfd, SIGKILL,
283 NULL, 0)) {
284 fprintf(stderr, "%s: kill failed: %m\n",
285 __func__);
286 return -1;
287 }
288 fd_peer_pidfd = -1;
289 }
290 break;
291 case COREDUMP_RECORD_END:
292 /* The coredump ends here and nothing follows it. */
293 if (record.len) {
294 fprintf(stderr, "%s: end record covers %llu bytes\n",
295 __func__,
296 (unsigned long long)record.len);
297 return -1;
298 }
299 ended = true;
300 break;
301 default:
302 fprintf(stderr, "%s: unknown record type %u\n",
303 __func__, record.type);
304 return -1;
305 }
306
307 size += record.len;
308 }
309
310 /* The end record is the last thing on the wire. */
311 if (recv(fd_coredump, &trailing, sizeof(trailing), MSG_DONTWAIT) > 0) {
312 fprintf(stderr, "%s: data after the end record\n", __func__);
313 return -1;
314 }
315
316 if (truncated)
317 *truncated = is_truncated;
318
319 *coredump_size = size;
320
321 fprintf(stderr, "Received %zd bytes for a %s coredump of %llu bytes\n",
322 received, is_truncated ? "truncated" : "complete",
323 (unsigned long long)size);
324 return received;
325 }
326
327 /* Reassemble a record stream into the coredump it describes. */
recv_coredump_records(int fd_coredump,int fd_core_file,off_t * coredump_size,bool * truncated,int fd_peer_pidfd)328 ssize_t recv_coredump_records(int fd_coredump, int fd_core_file,
329 off_t *coredump_size, bool *truncated,
330 int fd_peer_pidfd)
331 {
332 struct coredump_record_sink sink = {
333 .data = file_sink_data,
334 .zero = file_sink_zero,
335 .ctx = &fd_core_file,
336 };
337 ssize_t received;
338 off_t size = 0;
339
340 received = __recv_coredump_records(fd_coredump, &sink, &size, truncated,
341 fd_peer_pidfd);
342 if (received < 0)
343 return -1;
344
345 /*
346 * Nothing is written for a hole, so grow the file to the size the
347 * records describe in case the coredump ended in one.
348 */
349 if (ftruncate(fd_core_file, size) < 0) {
350 fprintf(stderr, "%s: ftruncate to %llu failed: %m\n",
351 __func__, (unsigned long long)size);
352 return -1;
353 }
354
355 if (coredump_size)
356 *coredump_size = size;
357
358 return received;
359 }
360
361 /* The ELF header of a native core file. */
is_core_ehdr(const ElfW (Ehdr)* ehdr)362 static bool is_core_ehdr(const ElfW(Ehdr) *ehdr)
363 {
364 return !memcmp(ehdr->e_ident, ELFMAG, SELFMAG) &&
365 ehdr->e_ident[EI_CLASS] == COREDUMP_ELFCLASS &&
366 ehdr->e_type == ET_CORE;
367 }
368
369 /* Whatever the server ends up with has to be an ELF core file. */
is_elf_core(int fd)370 bool is_elf_core(int fd)
371 {
372 ElfW(Ehdr) ehdr;
373
374 if (pread(fd, &ehdr, sizeof(ehdr), 0) != sizeof(ehdr)) {
375 fprintf(stderr, "%s: short read: %m\n", __func__);
376 return false;
377 }
378
379 if (!is_core_ehdr(&ehdr)) {
380 fprintf(stderr, "%s: not an ELF core file\n", __func__);
381 return false;
382 }
383
384 return true;
385 }
386
387 /*
388 * A coredump server that uploads to a blob store can't upload a sparse
389 * file and can't seek in the object it is uploading. It streams the data
390 * records into the object as they arrive, remembers the holes it left
391 * out, and uploads the program header table that describes the result
392 * last. What comes out is an ordinary ELF core file without the holes.
393 */
394
395 /* A run of the coredump the object doesn't carry. */
396 struct compact_hole {
397 __u64 offset;
398 __u64 len;
399 };
400
401 /* A program header of the object and where its bytes sat in the coredump. */
402 struct compact_piece {
403 ElfW(Phdr) phdr;
404 __u64 src;
405 };
406
407 struct compact_ctx {
408 int fd_body; /* the object's payload, append only */
409 int fd_reference; /* the coredump with its holes, for the test */
410 unsigned char *head; /* everything ahead of the segment data */
411 size_t head_len;
412 size_t head_cap;
413 __u64 data_offset; /* where the segment data starts, 0 while unknown */
414 struct compact_hole *holes;
415 size_t nr_holes;
416 size_t holes_cap;
417 __u64 body_len;
418 };
419
420 /* Write @len bytes out, short writes and all. */
compact_write(int fd,const void * buf,size_t len)421 static int compact_write(int fd, const void *buf, size_t len)
422 {
423 const unsigned char *pos = buf;
424
425 while (len) {
426 ssize_t ret = write(fd, pos, len);
427
428 if (ret <= 0) {
429 fprintf(stderr, "%s: write failed: %m\n", __func__);
430 return -1;
431 }
432
433 pos += ret;
434 len -= ret;
435 }
436
437 return 0;
438 }
439
440 /* Keep @len bytes of the head, or @len zeroes if @buf is NULL. */
compact_head_append(struct compact_ctx * ctx,const void * buf,size_t len)441 static int compact_head_append(struct compact_ctx *ctx, const void *buf,
442 size_t len)
443 {
444 if (ctx->head_len + len > ctx->head_cap) {
445 size_t cap = ctx->head_cap ? ctx->head_cap : PAGE_SIZE;
446 unsigned char *head;
447
448 while (cap < ctx->head_len + len)
449 cap *= 2;
450
451 head = realloc(ctx->head, cap);
452 if (!head) {
453 fprintf(stderr, "%s: out of memory\n", __func__);
454 return -1;
455 }
456 ctx->head = head;
457 ctx->head_cap = cap;
458 }
459
460 if (buf)
461 memcpy(ctx->head + ctx->head_len, buf, len);
462 else
463 memset(ctx->head + ctx->head_len, 0, len);
464 ctx->head_len += len;
465
466 return 0;
467 }
468
469 /* Remember a hole so the program header table can account for it later. */
compact_keep_hole(struct compact_ctx * ctx,__u64 offset,__u64 len)470 static int compact_keep_hole(struct compact_ctx *ctx, __u64 offset, __u64 len)
471 {
472 if (ctx->nr_holes == ctx->holes_cap) {
473 size_t cap = ctx->holes_cap ? ctx->holes_cap * 2 : 64;
474 struct compact_hole *holes;
475
476 holes = realloc(ctx->holes, cap * sizeof(*holes));
477 if (!holes) {
478 fprintf(stderr, "%s: out of memory\n", __func__);
479 return -1;
480 }
481 ctx->holes = holes;
482 ctx->holes_cap = cap;
483 }
484
485 ctx->holes[ctx->nr_holes].offset = offset;
486 ctx->holes[ctx->nr_holes].len = len;
487 ctx->nr_holes++;
488
489 return 0;
490 }
491
492 /* The segment data starts where the first PT_LOAD points. */
compact_probe(struct compact_ctx * ctx)493 static int compact_probe(struct compact_ctx *ctx)
494 {
495 const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr) *)ctx->head;
496 const ElfW(Phdr) *phdr;
497 size_t i;
498
499 if (ctx->data_offset || ctx->head_len < sizeof(*ehdr))
500 return 0;
501
502 if (!is_core_ehdr(ehdr)) {
503 fprintf(stderr, "%s: not an ELF core file\n", __func__);
504 return -1;
505 }
506
507 if (ehdr->e_phoff != sizeof(*ehdr) ||
508 ehdr->e_phentsize != sizeof(ElfW(Phdr)) ||
509 ehdr->e_phnum == 0 || ehdr->e_phnum == PN_XNUM) {
510 fprintf(stderr, "%s: unhandled program header table\n", __func__);
511 return -1;
512 }
513
514 if (ctx->head_len < ehdr->e_phoff +
515 (size_t)ehdr->e_phnum * ehdr->e_phentsize)
516 return 0;
517
518 phdr = (const ElfW(Phdr) *)(ctx->head + ehdr->e_phoff);
519 for (i = 0; i < ehdr->e_phnum; i++) {
520 if (phdr[i].p_type != PT_LOAD)
521 continue;
522 if (!ctx->data_offset || phdr[i].p_offset < ctx->data_offset)
523 ctx->data_offset = phdr[i].p_offset;
524 }
525
526 if (!ctx->data_offset) {
527 fprintf(stderr, "%s: coredump without a single segment\n",
528 __func__);
529 return -1;
530 }
531
532 return 0;
533 }
534
535 /*
536 * Take whatever of [@offset, @offset + @len) still belongs to the head.
537 * @buf is NULL for a hole. Returns how much was taken.
538 */
compact_head_take(struct compact_ctx * ctx,const void * buf,__u64 offset,__u64 len)539 static ssize_t compact_head_take(struct compact_ctx *ctx, const void *buf,
540 __u64 offset, __u64 len)
541 {
542 __u64 chunk;
543
544 if (!len || (ctx->data_offset && offset >= ctx->data_offset))
545 return 0;
546
547 chunk = len;
548 if (ctx->data_offset && offset + chunk > ctx->data_offset)
549 chunk = ctx->data_offset - offset;
550
551 if (offset != ctx->head_len) {
552 fprintf(stderr, "%s: head has a gap at %llu\n", __func__,
553 (unsigned long long)offset);
554 return -1;
555 }
556
557 if (compact_head_append(ctx, buf, chunk))
558 return -1;
559
560 return chunk;
561 }
562
compact_data(void * arg,const void * buf,size_t len,__u64 offset)563 static int compact_data(void *arg, const void *buf, size_t len, __u64 offset)
564 {
565 struct compact_ctx *ctx = arg;
566 const unsigned char *pos = buf;
567 ssize_t head;
568
569 /* Only the test needs a coredump with the holes still in it. */
570 if (pwrite(ctx->fd_reference, pos, len, offset) != (ssize_t)len) {
571 fprintf(stderr, "%s: pwrite failed: %m\n", __func__);
572 return -1;
573 }
574
575 /* The head has to be rewritten at the end, so hold on to it. */
576 head = compact_head_take(ctx, pos, offset, len);
577 if (head < 0)
578 return -1;
579 if (head && compact_probe(ctx))
580 return -1;
581
582 pos += head;
583 len -= head;
584 if (!len)
585 return 0;
586
587 /* Everything else goes into the object as it arrives. */
588 if (compact_write(ctx->fd_body, pos, len))
589 return -1;
590 ctx->body_len += len;
591
592 return 0;
593 }
594
compact_zero(void * arg,__u64 offset,__u64 len)595 static int compact_zero(void *arg, __u64 offset, __u64 len)
596 {
597 struct compact_ctx *ctx = arg;
598 ssize_t head;
599
600 /* A hole in the head is alignment padding. Write it out. */
601 head = compact_head_take(ctx, NULL, offset, len);
602 if (head < 0)
603 return -1;
604
605 offset += head;
606 len -= head;
607 if (!len)
608 return 0;
609
610 /* This is what the object doesn't have to carry. */
611 return compact_keep_hole(ctx, offset, len);
612 }
613
614 /* Where @offset ends up in the object once the holes ahead of it are gone. */
compact_offset(const struct compact_ctx * ctx,__u64 body_start,__u64 offset)615 static __u64 compact_offset(const struct compact_ctx *ctx, __u64 body_start,
616 __u64 offset)
617 {
618 __u64 elided = 0;
619 size_t i;
620
621 for (i = 0; i < ctx->nr_holes; i++) {
622 __u64 len = ctx->holes[i].len;
623
624 if (ctx->holes[i].offset >= offset)
625 break;
626 if (ctx->holes[i].offset + len > offset)
627 len = offset - ctx->holes[i].offset;
628 elided += len;
629 }
630
631 return body_start + (offset - ctx->data_offset) - elided;
632 }
633
634 /* A run of segment data that made it into the object. */
compact_add_data(struct compact_piece * pieces,size_t * nr,const ElfW (Phdr)* phdr,__u64 start,__u64 end)635 static void compact_add_data(struct compact_piece *pieces, size_t *nr,
636 const ElfW(Phdr) *phdr, __u64 start, __u64 end)
637 {
638 struct compact_piece *piece = &pieces[(*nr)++];
639
640 piece->phdr = *phdr;
641 piece->phdr.p_vaddr = phdr->p_vaddr + (start - phdr->p_offset);
642 piece->phdr.p_paddr = 0;
643 piece->phdr.p_filesz = end - start;
644 piece->phdr.p_memsz = end - start;
645 piece->src = start;
646 }
647
648 /*
649 * A run of @len bytes the object doesn't carry. It grows the piece in
650 * front of it if this segment already has one, because everything a
651 * segment covers past p_filesz is zeroes anyway.
652 */
compact_add_zero(struct compact_piece * pieces,size_t * nr,size_t first,const ElfW (Phdr)* phdr,__u64 vaddr,__u64 len)653 static void compact_add_zero(struct compact_piece *pieces, size_t *nr,
654 size_t first, const ElfW(Phdr) *phdr, __u64 vaddr,
655 __u64 len)
656 {
657 struct compact_piece *piece;
658
659 if (*nr > first) {
660 pieces[*nr - 1].phdr.p_memsz += len;
661 return;
662 }
663
664 piece = &pieces[(*nr)++];
665 piece->phdr = *phdr;
666 piece->phdr.p_vaddr = vaddr;
667 piece->phdr.p_paddr = 0;
668 piece->phdr.p_filesz = 0;
669 piece->phdr.p_memsz = len;
670 piece->src = 0;
671 }
672
673 /* Split the segments at the holes and write out what the object became. */
compact_build(struct compact_ctx * ctx,int fd_object)674 static int compact_build(struct compact_ctx *ctx, int fd_object)
675 {
676 __u64 note_offset = 0, note_len = 0, note_new;
677 __u64 align = 0, head_len, body_start, pos;
678 size_t nr_old, nr_new = 0, note_piece = 0, i;
679 struct compact_piece *pieces;
680 char buffer[PAGE_SIZE];
681 const ElfW(Phdr) *old;
682 ElfW(Ehdr) ehdr;
683 int ret = -1;
684
685 if (!ctx->data_offset) {
686 fprintf(stderr, "%s: coredump without segment data\n", __func__);
687 return -1;
688 }
689
690 memcpy(&ehdr, ctx->head, sizeof(ehdr));
691 if (ehdr.e_shoff) {
692 fprintf(stderr, "%s: section headers are not handled\n",
693 __func__);
694 return -1;
695 }
696
697 old = (const ElfW(Phdr) *)(ctx->head + ehdr.e_phoff);
698 nr_old = ehdr.e_phnum;
699
700 pieces = calloc(nr_old + 2 * ctx->nr_holes + 1, sizeof(*pieces));
701 if (!pieces) {
702 fprintf(stderr, "%s: out of memory\n", __func__);
703 return -1;
704 }
705
706 for (i = 0; i < nr_old; i++) {
707 ElfW(Phdr) phdr = old[i];
708 __u64 end = phdr.p_offset + phdr.p_filesz;
709 __u64 cur = phdr.p_offset;
710 size_t first = nr_new, h;
711
712 /* The notes move because the table in front of them grows. */
713 if (phdr.p_type == PT_NOTE) {
714 if (note_len) {
715 fprintf(stderr, "%s: more than one note segment\n",
716 __func__);
717 goto out;
718 }
719 note_offset = phdr.p_offset;
720 note_len = phdr.p_filesz;
721 note_piece = nr_new;
722 pieces[nr_new].phdr = phdr;
723 pieces[nr_new++].src = 0;
724 continue;
725 }
726
727 if (phdr.p_type != PT_LOAD) {
728 if (phdr.p_filesz && phdr.p_offset < ctx->data_offset) {
729 fprintf(stderr, "%s: segment %zu is in the head\n",
730 __func__, i);
731 goto out;
732 }
733 pieces[nr_new].phdr = phdr;
734 pieces[nr_new++].src = phdr.p_offset;
735 continue;
736 }
737
738 if (!align)
739 align = phdr.p_align;
740
741 for (h = 0; h < ctx->nr_holes && cur < end; h++) {
742 __u64 start = ctx->holes[h].offset;
743 __u64 stop = start + ctx->holes[h].len;
744
745 if (stop <= cur)
746 continue;
747 if (start >= end)
748 break;
749
750 /* A hole can span more than this one segment. */
751 if (start < cur)
752 start = cur;
753 if (stop > end)
754 stop = end;
755
756 if (start > cur) {
757 compact_add_data(pieces, &nr_new, &phdr, cur,
758 start);
759 cur = start;
760 }
761 compact_add_zero(pieces, &nr_new, first, &phdr,
762 phdr.p_vaddr + (cur - phdr.p_offset),
763 stop - cur);
764 cur = stop;
765 }
766
767 if (cur < end)
768 compact_add_data(pieces, &nr_new, &phdr, cur, end);
769
770 /* Whatever the kernel didn't dump of this mapping. */
771 if (phdr.p_memsz > phdr.p_filesz)
772 compact_add_zero(pieces, &nr_new, first, &phdr,
773 phdr.p_vaddr + phdr.p_filesz,
774 phdr.p_memsz - phdr.p_filesz);
775 }
776
777 if (!note_len || note_offset + note_len > ctx->head_len) {
778 fprintf(stderr, "%s: notes aren't where they should be\n",
779 __func__);
780 goto out;
781 }
782
783 if (nr_new >= PN_XNUM) {
784 fprintf(stderr, "%s: %zu program headers don't fit\n", __func__,
785 nr_new);
786 goto out;
787 }
788
789 if (!align || (align & (align - 1)))
790 align = sysconf(_SC_PAGESIZE);
791
792 note_new = sizeof(ehdr) + (__u64)nr_new * sizeof(ElfW(Phdr));
793 head_len = note_new + note_len;
794 body_start = (head_len + align - 1) & ~(align - 1);
795
796 for (i = 0; i < nr_new; i++) {
797 struct compact_piece *piece = &pieces[i];
798
799 if (i == note_piece)
800 piece->phdr.p_offset = note_new;
801 else if (piece->phdr.p_filesz)
802 piece->phdr.p_offset = compact_offset(ctx, body_start,
803 piece->src);
804 else
805 piece->phdr.p_offset = 0;
806 }
807
808 /* Only now is the head known. That's why it is uploaded last. */
809 ehdr.e_phnum = nr_new;
810 if (compact_write(fd_object, &ehdr, sizeof(ehdr)))
811 goto out;
812
813 for (i = 0; i < nr_new; i++)
814 if (compact_write(fd_object, &pieces[i].phdr,
815 sizeof(pieces[i].phdr)))
816 goto out;
817
818 if (compact_write(fd_object, ctx->head + note_offset, note_len))
819 goto out;
820
821 /* Keep the segments aligned the way a debugger expects them. */
822 memset(buffer, 0, sizeof(buffer));
823 for (pos = head_len; pos < body_start; ) {
824 __u64 chunk = body_start - pos;
825
826 if (chunk > sizeof(buffer))
827 chunk = sizeof(buffer);
828 if (compact_write(fd_object, buffer, chunk))
829 goto out;
830 pos += chunk;
831 }
832
833 /* Putting the parts together is the blob store's job. Do it here. */
834 for (pos = 0; pos < ctx->body_len; ) {
835 ssize_t chunk = pread(ctx->fd_body, buffer, sizeof(buffer), pos);
836
837 if (chunk <= 0) {
838 fprintf(stderr, "%s: short read %zd: %m\n", __func__,
839 chunk);
840 goto out;
841 }
842 if (compact_write(fd_object, buffer, chunk))
843 goto out;
844 pos += chunk;
845 }
846
847 fprintf(stderr, "Object is %llu bytes in %zu program headers, %zu holes left out\n",
848 (unsigned long long)(body_start + ctx->body_len), nr_new,
849 ctx->nr_holes);
850 ret = 0;
851 out:
852 free(pieces);
853 return ret;
854 }
855
856 /*
857 * Reassemble a record stream into an ELF core file that has no holes in
858 * it, the way a coredump server that uploads to a blob store has to. If
859 * @fd_reference is valid it gets the coredump the records describe,
860 * holes and all, so the test can compare the two.
861 */
recv_coredump_compact(int fd_coredump,int fd_object,int fd_reference,off_t * coredump_size)862 ssize_t recv_coredump_compact(int fd_coredump, int fd_object, int fd_reference,
863 off_t *coredump_size)
864 {
865 struct compact_ctx ctx = {
866 .fd_body = -1,
867 .fd_reference = fd_reference,
868 };
869 struct coredump_record_sink sink = {
870 .data = compact_data,
871 .zero = compact_zero,
872 .ctx = &ctx,
873 };
874 ssize_t received;
875 off_t size = 0;
876 FILE *body;
877
878 body = tmpfile();
879 if (!body) {
880 fprintf(stderr, "%s: tmpfile failed: %m\n", __func__);
881 return -1;
882 }
883 ctx.fd_body = fileno(body);
884
885 /* An upload is appended to. Make sure nothing here can seek. */
886 if (fcntl(ctx.fd_body, F_SETFL, O_APPEND)) {
887 fprintf(stderr, "%s: F_SETFL failed: %m\n", __func__);
888 received = -1;
889 goto out;
890 }
891
892 received = __recv_coredump_records(fd_coredump, &sink, &size, NULL, -1);
893 if (received < 0)
894 goto out;
895
896 /*
897 * Nothing is written for a hole, so grow the reference to the size
898 * the records describe in case the coredump ended in one.
899 */
900 if (ftruncate(fd_reference, size) < 0) {
901 fprintf(stderr, "%s: ftruncate to %llu failed: %m\n",
902 __func__, (unsigned long long)size);
903 received = -1;
904 goto out;
905 }
906
907 if (compact_build(&ctx, fd_object)) {
908 received = -1;
909 goto out;
910 }
911
912 if (coredump_size)
913 *coredump_size = size;
914 out:
915 fclose(body);
916 free(ctx.head);
917 free(ctx.holes);
918 return received;
919 }
920
921 /* Read the ELF header and the program header table of @fd. */
ElfW(Phdr)922 static ElfW(Phdr) *read_phdrs(int fd, size_t *nr)
923 {
924 ElfW(Ehdr) ehdr;
925 ElfW(Phdr) *phdr;
926 size_t size;
927
928 if (pread(fd, &ehdr, sizeof(ehdr), 0) != sizeof(ehdr)) {
929 fprintf(stderr, "%s: no ELF header: %m\n", __func__);
930 return NULL;
931 }
932
933 if (!is_core_ehdr(&ehdr) || !ehdr.e_phnum ||
934 ehdr.e_phentsize != sizeof(*phdr)) {
935 fprintf(stderr, "%s: not an ELF core file\n", __func__);
936 return NULL;
937 }
938
939 size = (size_t)ehdr.e_phnum * ehdr.e_phentsize;
940 phdr = malloc(size);
941 if (!phdr) {
942 fprintf(stderr, "%s: out of memory\n", __func__);
943 return NULL;
944 }
945
946 if (pread(fd, phdr, size, ehdr.e_phoff) != (ssize_t)size) {
947 fprintf(stderr, "%s: short program header table: %m\n", __func__);
948 free(phdr);
949 return NULL;
950 }
951
952 *nr = ehdr.e_phnum;
953 return phdr;
954 }
955
956 /* The segment @vaddr falls into. */
ElfW(Phdr)957 static const ElfW(Phdr) *find_segment(const ElfW(Phdr) *phdr, size_t nr,
958 __u64 vaddr)
959 {
960 size_t i;
961
962 for (i = 0; i < nr; i++) {
963 if (phdr[i].p_type != PT_LOAD)
964 continue;
965 if (vaddr >= phdr[i].p_vaddr &&
966 vaddr < phdr[i].p_vaddr + phdr[i].p_memsz)
967 return &phdr[i];
968 }
969
970 return NULL;
971 }
972
973 /* The PT_LOAD segment @vaddr falls into. */
find_coredump_segment(int fd,__u64 vaddr,ElfW (Phdr)* segment)974 bool find_coredump_segment(int fd, __u64 vaddr, ElfW(Phdr) *segment)
975 {
976 const ElfW(Phdr) *found;
977 ElfW(Phdr) *phdr;
978 size_t nr;
979
980 phdr = read_phdrs(fd, &nr);
981 if (!phdr)
982 return false;
983
984 found = find_segment(phdr, nr, vaddr);
985 if (found)
986 *segment = *found;
987 else
988 fprintf(stderr, "%s: no segment for 0x%llx\n", __func__,
989 (unsigned long long)vaddr);
990
991 free(phdr);
992 return found;
993 }
994
995 /* How many bytes the PT_LOAD and the PT_NOTE segments of @fd carry. */
sum_coredump_segments(int fd,__u64 * data,__u64 * notes)996 bool sum_coredump_segments(int fd, __u64 *data, __u64 *notes)
997 {
998 ElfW(Phdr) *phdr;
999 size_t nr, i;
1000
1001 phdr = read_phdrs(fd, &nr);
1002 if (!phdr)
1003 return false;
1004
1005 *data = 0;
1006 *notes = 0;
1007 for (i = 0; i < nr; i++) {
1008 if (phdr[i].p_type == PT_LOAD)
1009 *data += phdr[i].p_filesz;
1010 else if (phdr[i].p_type == PT_NOTE)
1011 *notes += phdr[i].p_filesz;
1012 }
1013
1014 free(phdr);
1015 return true;
1016 }
1017
1018 /* The coredump in @fd is at least as long as every segment it declares. */
check_coredump_extent(int fd)1019 bool check_coredump_extent(int fd)
1020 {
1021 ElfW(Phdr) *phdr;
1022 struct stat st;
1023 size_t nr, i;
1024 bool ok = true;
1025
1026 if (fstat(fd, &st)) {
1027 fprintf(stderr, "%s: fstat: %m\n", __func__);
1028 return false;
1029 }
1030
1031 phdr = read_phdrs(fd, &nr);
1032 if (!phdr)
1033 return false;
1034
1035 for (i = 0; i < nr; i++) {
1036 if (phdr[i].p_offset + phdr[i].p_filesz <= (__u64)st.st_size)
1037 continue;
1038 fprintf(stderr, "%s: segment %zu ends at %llu, the coredump at %llu\n",
1039 __func__, i,
1040 (unsigned long long)(phdr[i].p_offset + phdr[i].p_filesz),
1041 (unsigned long long)st.st_size);
1042 ok = false;
1043 }
1044
1045 free(phdr);
1046 return ok;
1047 }
1048
1049 /* The next stretch of memory the segments cover, split ones merged back. */
next_range(const ElfW (Phdr)* phdr,size_t nr,size_t * i,__u64 * start,__u64 * end)1050 static bool next_range(const ElfW(Phdr) *phdr, size_t nr, size_t *i,
1051 __u64 *start, __u64 *end)
1052 {
1053 while (*i < nr && phdr[*i].p_type != PT_LOAD)
1054 (*i)++;
1055
1056 if (*i >= nr)
1057 return false;
1058
1059 *start = phdr[*i].p_vaddr;
1060 *end = phdr[*i].p_vaddr + phdr[*i].p_memsz;
1061 (*i)++;
1062
1063 while (*i < nr) {
1064 if (phdr[*i].p_type != PT_LOAD) {
1065 (*i)++;
1066 continue;
1067 }
1068 if (phdr[*i].p_vaddr != *end)
1069 break;
1070 *end = phdr[*i].p_vaddr + phdr[*i].p_memsz;
1071 (*i)++;
1072 }
1073
1074 return true;
1075 }
1076
1077 /* Compare @len bytes at @offset against @len bytes at @offset_ref. */
compare_range(int fd,__u64 offset,int fd_ref,__u64 offset_ref,__u64 len)1078 static int compare_range(int fd, __u64 offset, int fd_ref, __u64 offset_ref,
1079 __u64 len)
1080 {
1081 char buffer[PAGE_SIZE], buffer_ref[PAGE_SIZE];
1082
1083 while (len) {
1084 size_t chunk = len < sizeof(buffer) ? len : sizeof(buffer);
1085
1086 if (pread(fd, buffer, chunk, offset) != (ssize_t)chunk ||
1087 pread(fd_ref, buffer_ref, chunk, offset_ref) != (ssize_t)chunk) {
1088 fprintf(stderr, "%s: short read at %llu: %m\n",
1089 __func__, (unsigned long long)offset);
1090 return -1;
1091 }
1092
1093 if (memcmp(buffer, buffer_ref, chunk)) {
1094 fprintf(stderr, "%s: %llu differs from %llu\n", __func__,
1095 (unsigned long long)offset,
1096 (unsigned long long)offset_ref);
1097 return -1;
1098 }
1099
1100 offset += chunk;
1101 offset_ref += chunk;
1102 len -= chunk;
1103 }
1104
1105 return 0;
1106 }
1107
1108 /* The @len bytes at @offset the object left out have to have been zeroes. */
check_zero_range(int fd,__u64 offset,__u64 len)1109 static int check_zero_range(int fd, __u64 offset, __u64 len)
1110 {
1111 static const char zeroes[PAGE_SIZE];
1112 char buffer[PAGE_SIZE];
1113
1114 while (len) {
1115 size_t chunk = len < sizeof(buffer) ? len : sizeof(buffer);
1116
1117 if (pread(fd, buffer, chunk, offset) != (ssize_t)chunk) {
1118 fprintf(stderr, "%s: short read at %llu: %m\n",
1119 __func__, (unsigned long long)offset);
1120 return -1;
1121 }
1122
1123 if (memcmp(buffer, zeroes, chunk)) {
1124 fprintf(stderr, "%s: %llu isn't a hole\n", __func__,
1125 (unsigned long long)offset);
1126 return -1;
1127 }
1128
1129 offset += chunk;
1130 len -= chunk;
1131 }
1132
1133 return 0;
1134 }
1135
1136 /*
1137 * The object has to describe the same memory as the coredump it was built
1138 * from, and it has to describe it correctly.
1139 */
check_compact_coredump(int fd_object,int fd_reference)1140 int check_compact_coredump(int fd_object, int fd_reference)
1141 {
1142 ElfW(Phdr) *object = NULL, *reference = NULL;
1143 size_t nr_object, nr_reference, i;
1144 size_t io = 0, ir = 0;
1145 int ret = -1;
1146
1147 object = read_phdrs(fd_object, &nr_object);
1148 reference = read_phdrs(fd_reference, &nr_reference);
1149 if (!object || !reference)
1150 goto out;
1151
1152 /* Nothing may have been dropped and nothing may have been added. */
1153 for (;;) {
1154 __u64 start = 0, end = 0, start_ref = 0, end_ref = 0;
1155 bool has, has_ref;
1156
1157 has = next_range(object, nr_object, &io, &start, &end);
1158 has_ref = next_range(reference, nr_reference, &ir, &start_ref,
1159 &end_ref);
1160 if (!has && !has_ref)
1161 break;
1162
1163 if (has != has_ref || start != start_ref || end != end_ref) {
1164 fprintf(stderr, "%s: object covers 0x%llx-0x%llx, coredump 0x%llx-0x%llx\n",
1165 __func__, (unsigned long long)start,
1166 (unsigned long long)end,
1167 (unsigned long long)start_ref,
1168 (unsigned long long)end_ref);
1169 goto out;
1170 }
1171 }
1172
1173 for (i = 0; i < nr_object; i++) {
1174 const ElfW(Phdr) *segment;
1175 __u64 offset, dumped;
1176
1177 if (object[i].p_type != PT_LOAD || !object[i].p_memsz)
1178 continue;
1179
1180 segment = find_segment(reference, nr_reference,
1181 object[i].p_vaddr);
1182 if (!segment) {
1183 fprintf(stderr, "%s: 0x%llx isn't in the coredump\n",
1184 __func__,
1185 (unsigned long long)object[i].p_vaddr);
1186 goto out;
1187 }
1188
1189 offset = object[i].p_vaddr - segment->p_vaddr;
1190 dumped = offset < segment->p_filesz ?
1191 segment->p_filesz - offset : 0;
1192
1193 /* What the object carries is what the coredump had. */
1194 if (object[i].p_filesz > dumped) {
1195 fprintf(stderr, "%s: object carries %llu bytes the coredump doesn't have\n",
1196 __func__,
1197 (unsigned long long)(object[i].p_filesz - dumped));
1198 goto out;
1199 }
1200
1201 if (compare_range(fd_object, object[i].p_offset, fd_reference,
1202 segment->p_offset + offset,
1203 object[i].p_filesz))
1204 goto out;
1205
1206 /* And what it left out was a hole. */
1207 if (object[i].p_memsz > object[i].p_filesz &&
1208 dumped > object[i].p_filesz) {
1209 __u64 left_out = dumped - object[i].p_filesz;
1210
1211 if (left_out > object[i].p_memsz - object[i].p_filesz)
1212 left_out = object[i].p_memsz - object[i].p_filesz;
1213
1214 if (check_zero_range(fd_reference,
1215 segment->p_offset + offset +
1216 object[i].p_filesz, left_out))
1217 goto out;
1218 }
1219 }
1220
1221 ret = 0;
1222 out:
1223 free(object);
1224 free(reference);
1225 return ret;
1226 }
1227
1228 /* Read a plain coredump byte stream to end-of-file. */
recv_coredump_bytes(int fd_coredump,int fd_core_file)1229 ssize_t recv_coredump_bytes(int fd_coredump, int fd_core_file)
1230 {
1231 ssize_t received = 0;
1232
1233 for (;;) {
1234 char buffer[PAGE_SIZE];
1235 ssize_t ret = read_nointr(fd_coredump, buffer, sizeof(buffer));
1236
1237 if (ret < 0) {
1238 fprintf(stderr, "%s: read failed: %m\n", __func__);
1239 return -1;
1240 }
1241 if (ret == 0)
1242 break;
1243
1244 if (write_nointr(fd_core_file, buffer, ret) != ret) {
1245 fprintf(stderr, "%s: write failed: %m\n", __func__);
1246 return -1;
1247 }
1248 received += ret;
1249 }
1250
1251 fprintf(stderr, "Received %zd bytes of coredump\n", received);
1252 return received;
1253 }
1254
crashing_thread(void * arg)1255 static void *crashing_thread(void *arg)
1256 {
1257 int *p;
1258
1259 (void)arg;
1260
1261 /* crash on purpose with SEGV_MAPERR */
1262 p = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
1263 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1264 if (p == MAP_FAILED)
1265 return NULL;
1266 munmap(p, PAGE_SIZE);
1267 *p = 0;
1268
1269 return NULL;
1270 }
1271
crashing_child_thread(void)1272 void crashing_child_thread(void)
1273 {
1274 pthread_t thread;
1275 int i;
1276
1277 for (i = 0; i < NUM_THREAD_SPAWN; ++i)
1278 pthread_create(&thread, NULL, do_nothing, NULL);
1279
1280 /* crash from a non-leader thread */
1281 pthread_create(&thread, NULL, crashing_thread, NULL);
1282 pause();
1283 }
1284
create_detached_tmpfs(void)1285 int create_detached_tmpfs(void)
1286 {
1287 int fd_context, fd_tmpfs;
1288
1289 fd_context = sys_fsopen("tmpfs", 0);
1290 if (fd_context < 0)
1291 return -1;
1292
1293 if (sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0)
1294 return -1;
1295
1296 fd_tmpfs = sys_fsmount(fd_context, 0, 0);
1297 close(fd_context);
1298 return fd_tmpfs;
1299 }
1300
create_and_listen_unix_socket(const char * path)1301 int create_and_listen_unix_socket(const char *path)
1302 {
1303 struct sockaddr_un addr = {
1304 .sun_family = AF_UNIX,
1305 };
1306 assert(strlen(path) < sizeof(addr.sun_path) - 1);
1307 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
1308 size_t addr_len =
1309 offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1;
1310 int fd, ret;
1311
1312 fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
1313 if (fd < 0)
1314 goto out;
1315
1316 ret = bind(fd, (const struct sockaddr *)&addr, addr_len);
1317 if (ret < 0)
1318 goto out;
1319
1320 ret = listen(fd, 128);
1321 if (ret < 0)
1322 goto out;
1323
1324 return fd;
1325
1326 out:
1327 fprintf(stderr, "%s: %s: %m\n", __func__, path);
1328 if (fd >= 0)
1329 close(fd);
1330 return -1;
1331 }
1332
set_core_pattern(const char * pattern)1333 bool set_core_pattern(const char *pattern)
1334 {
1335 int fd;
1336 ssize_t ret;
1337
1338 fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC);
1339 if (fd < 0)
1340 return false;
1341
1342 ret = write(fd, pattern, strlen(pattern));
1343 close(fd);
1344 if (ret < 0)
1345 return false;
1346
1347 fprintf(stderr, "Set core_pattern to '%s' | %zu == %zu\n", pattern, ret, strlen(pattern));
1348 return ret == strlen(pattern);
1349 }
1350
get_peer_pidfd(int fd)1351 int get_peer_pidfd(int fd)
1352 {
1353 int fd_peer_pidfd;
1354 socklen_t fd_peer_pidfd_len = sizeof(fd_peer_pidfd);
1355 int ret = getsockopt(fd, SOL_SOCKET, SO_PEERPIDFD, &fd_peer_pidfd,
1356 &fd_peer_pidfd_len);
1357 if (ret < 0) {
1358 fprintf(stderr, "get_peer_pidfd: getsockopt(SO_PEERPIDFD) failed: %m\n");
1359 return -1;
1360 }
1361 fprintf(stderr, "get_peer_pidfd: successfully retrieved pidfd %d\n", fd_peer_pidfd);
1362 return fd_peer_pidfd;
1363 }
1364
get_peer_pidfd_thread(int fd)1365 int get_peer_pidfd_thread(int fd)
1366 {
1367 int fd_peer_pidfd;
1368 socklen_t fd_peer_pidfd_len = sizeof(fd_peer_pidfd);
1369 int ret = getsockopt(fd, SOL_SOCKET, SO_PEERPIDFD_THREAD, &fd_peer_pidfd,
1370 &fd_peer_pidfd_len);
1371 if (ret < 0) {
1372 fprintf(stderr, "%s: getsockopt(SO_PEERPIDFD_THREAD) failed: %m\n", __func__);
1373 return -1;
1374 }
1375 fprintf(stderr, "%s: successfully retrieved pidfd %d\n", __func__, fd_peer_pidfd);
1376 return fd_peer_pidfd;
1377 }
1378
get_pidfd_info(int fd_peer_pidfd,struct pidfd_info * info)1379 bool get_pidfd_info(int fd_peer_pidfd, struct pidfd_info *info)
1380 {
1381 int ret;
1382 memset(info, 0, sizeof(*info));
1383 info->mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL;
1384 ret = ioctl(fd_peer_pidfd, PIDFD_GET_INFO, info);
1385 if (ret < 0) {
1386 fprintf(stderr, "get_pidfd_info: ioctl(PIDFD_GET_INFO) failed: %m\n");
1387 return false;
1388 }
1389 fprintf(stderr, "get_pidfd_info: mask=0x%llx, coredump_mask=0x%x, coredump_signal=%d, coredump_code=%d\n",
1390 (unsigned long long)info->mask, info->coredump_mask, info->coredump_signal, info->coredump_code);
1391 return true;
1392 }
1393
1394 /*
1395 * How much the peer has mapped. The task is parked in the coredump
1396 * handshake, so its mm is still there to be looked at.
1397 */
peer_vm_size(int fd_peer_pidfd)1398 ssize_t peer_vm_size(int fd_peer_pidfd)
1399 {
1400 struct pidfd_info info = {};
1401 unsigned long pages;
1402 char path[64];
1403 FILE *f;
1404
1405 if (!get_pidfd_info(fd_peer_pidfd, &info))
1406 return -1;
1407
1408 snprintf(path, sizeof(path), "/proc/%d/statm", info.pid);
1409 f = fopen(path, "r");
1410 if (!f) {
1411 fprintf(stderr, "%s: %s: %m\n", __func__, path);
1412 return -1;
1413 }
1414
1415 if (fscanf(f, "%lu", &pages) != 1) {
1416 fprintf(stderr, "%s: %s: no size\n", __func__, path);
1417 fclose(f);
1418 return -1;
1419 }
1420 fclose(f);
1421
1422 return (ssize_t)pages * sysconf(_SC_PAGESIZE);
1423 }
1424
1425 /* Protocol helper functions */
1426
1427 /* The peer's /proc/<pid>/coredump_filter, which is in memory types. */
peer_coredump_filter(int fd_peer_pidfd,__u64 * memory_types)1428 bool peer_coredump_filter(int fd_peer_pidfd, __u64 *memory_types)
1429 {
1430 struct pidfd_info info = {};
1431 unsigned long value;
1432 char path[64];
1433 FILE *f;
1434 int ret;
1435
1436 if (!get_pidfd_info(fd_peer_pidfd, &info))
1437 return false;
1438
1439 snprintf(path, sizeof(path), "/proc/%d/coredump_filter", info.pid);
1440 f = fopen(path, "r");
1441 if (!f) {
1442 fprintf(stderr, "%s: %s: %m\n", __func__, path);
1443 return false;
1444 }
1445
1446 ret = fscanf(f, "%lx", &value);
1447 fclose(f);
1448 if (ret != 1) {
1449 fprintf(stderr, "%s: %s: no value\n", __func__, path);
1450 return false;
1451 }
1452
1453 *memory_types = value;
1454 return true;
1455 }
1456
1457 /* Read @len bytes at @addr from the peer's /proc/<pid>/mem. */
peer_read_mem(int fd_peer_pidfd,__u64 addr,void * buf,size_t len)1458 ssize_t peer_read_mem(int fd_peer_pidfd, __u64 addr, void *buf, size_t len)
1459 {
1460 struct pidfd_info info = {};
1461 char path[64];
1462 ssize_t ret;
1463 int fd;
1464
1465 if (!get_pidfd_info(fd_peer_pidfd, &info))
1466 return -1;
1467
1468 snprintf(path, sizeof(path), "/proc/%d/mem", info.pid);
1469 fd = open(path, O_RDONLY | O_CLOEXEC);
1470 if (fd < 0) {
1471 fprintf(stderr, "%s: %s: %m\n", __func__, path);
1472 return -1;
1473 }
1474
1475 ret = pread(fd, buf, len, addr);
1476 if (ret < 0)
1477 fprintf(stderr, "%s: %s at 0x%llx: %m\n", __func__, path,
1478 (unsigned long long)addr);
1479 close(fd);
1480 return ret;
1481 }
1482
recv_marker(int fd)1483 ssize_t recv_marker(int fd)
1484 {
1485 enum coredump_mark mark = COREDUMP_MARK_REQACK;
1486 ssize_t ret;
1487
1488 ret = recv(fd, &mark, sizeof(mark), MSG_WAITALL);
1489 if (ret != sizeof(mark))
1490 return -1;
1491
1492 switch (mark) {
1493 case COREDUMP_MARK_REQACK:
1494 fprintf(stderr, "Received marker: ReqAck\n");
1495 return COREDUMP_MARK_REQACK;
1496 case COREDUMP_MARK_MINSIZE:
1497 fprintf(stderr, "Received marker: MinSize\n");
1498 return COREDUMP_MARK_MINSIZE;
1499 case COREDUMP_MARK_MAXSIZE:
1500 fprintf(stderr, "Received marker: MaxSize\n");
1501 return COREDUMP_MARK_MAXSIZE;
1502 case COREDUMP_MARK_UNSUPPORTED:
1503 fprintf(stderr, "Received marker: Unsupported\n");
1504 return COREDUMP_MARK_UNSUPPORTED;
1505 case COREDUMP_MARK_CONFLICTING:
1506 fprintf(stderr, "Received marker: Conflicting\n");
1507 return COREDUMP_MARK_CONFLICTING;
1508 default:
1509 fprintf(stderr, "Received unknown marker: %u\n", mark);
1510 break;
1511 }
1512 return -1;
1513 }
1514
read_marker(int fd,enum coredump_mark mark)1515 bool read_marker(int fd, enum coredump_mark mark)
1516 {
1517 ssize_t ret;
1518
1519 ret = recv_marker(fd);
1520 if (ret < 0)
1521 return false;
1522 return ret == mark;
1523 }
1524
1525 /*
1526 * The kernel hung up without sending anything more: end of stream, or a
1527 * reset if it refused the ack on its peeked size and never read it.
1528 */
read_hangup(int fd)1529 bool read_hangup(int fd)
1530 {
1531 ssize_t ret;
1532 char c;
1533
1534 ret = recv(fd, &c, sizeof(c), MSG_WAITALL);
1535 if (ret == 0) {
1536 fprintf(stderr, "Kernel closed the connection\n");
1537 return true;
1538 }
1539 if (ret < 0 && errno == ECONNRESET) {
1540 fprintf(stderr, "Kernel closed the connection with the ack unread\n");
1541 return true;
1542 }
1543
1544 fprintf(stderr, "%s: expected a hangup, got %zd: %m\n", __func__, ret);
1545 return false;
1546 }
1547
1548 /* Read the request as a server built with a @user_size byte struct does. */
read_coredump_req_sized(int fd,struct coredump_req * req,size_t user_size)1549 bool read_coredump_req_sized(int fd, struct coredump_req *req, size_t user_size)
1550 {
1551 ssize_t ret;
1552 size_t field_size, known_size, kernel_size, remaining_size;
1553
1554 memset(req, 0, sizeof(*req));
1555 field_size = sizeof(req->size);
1556
1557 /* Peek the size of the coredump request. */
1558 ret = recv(fd, req, field_size, MSG_PEEK | MSG_WAITALL);
1559 if (ret != field_size) {
1560 fprintf(stderr, "%s: peek failed (got %zd, expected %zu): %m\n", __func__,
1561 ret, field_size);
1562 return false;
1563 }
1564 kernel_size = req->size;
1565
1566 if (kernel_size < COREDUMP_REQ_SIZE_VER0) {
1567 fprintf(stderr, "%s: kernel_size %zu < min %d\n", __func__,
1568 kernel_size, COREDUMP_REQ_SIZE_VER0);
1569 return false;
1570 }
1571 if (kernel_size >= PAGE_SIZE) {
1572 fprintf(stderr, "%s: kernel_size %zu >= PAGE_SIZE %d\n", __func__,
1573 kernel_size, PAGE_SIZE);
1574 return false;
1575 }
1576
1577 /* Consume as much of the request as we know about. */
1578 known_size = user_size < kernel_size ? user_size : kernel_size;
1579 ret = recv(fd, req, known_size, MSG_WAITALL);
1580 if (ret != known_size)
1581 return false;
1582
1583 fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n",
1584 req->size, (unsigned long long)req->mask);
1585
1586 if (kernel_size > user_size)
1587 remaining_size = kernel_size - user_size;
1588 else
1589 remaining_size = 0;
1590
1591 if (PAGE_SIZE <= remaining_size)
1592 return false;
1593
1594 /*
1595 * Discard any additional data if the kernel's request was larger than
1596 * what we knew about or cared about.
1597 */
1598 if (remaining_size) {
1599 char buffer[PAGE_SIZE];
1600
1601 ret = recv(fd, buffer, remaining_size, MSG_WAITALL);
1602 if (ret != remaining_size)
1603 return false;
1604 fprintf(stderr, "Discarded %zu bytes of data after coredump request\n", remaining_size);
1605 }
1606
1607 return true;
1608 }
1609
read_coredump_req(int fd,struct coredump_req * req)1610 bool read_coredump_req(int fd, struct coredump_req *req)
1611 {
1612 return read_coredump_req_sized(fd, req, sizeof(*req));
1613 }
1614
1615 /* Send @len bytes of @ack as they are, more than the struct if asked to. */
send_coredump_ack_bytes(int fd,const struct coredump_ack * ack,size_t len)1616 bool send_coredump_ack_bytes(int fd, const struct coredump_ack *ack, size_t len)
1617 {
1618 ssize_t ret;
1619 /*
1620 * Wrap struct coredump_ack in a larger struct so we can
1621 * simulate sending to much data to the kernel.
1622 */
1623 struct large_ack_for_size_testing {
1624 struct coredump_ack ack;
1625 char buffer[PAGE_SIZE];
1626 } large_ack = {};
1627
1628 if (len > sizeof(large_ack))
1629 return false;
1630
1631 large_ack.ack = *ack;
1632 ret = send(fd, &large_ack, len, MSG_NOSIGNAL);
1633 if (ret != len) {
1634 fprintf(stderr, "%s: short send %zd: %m\n", __func__, ret);
1635 return false;
1636 }
1637
1638 fprintf(stderr, "Sent %zu bytes of coredump ack: size %u, mask 0x%llx, types 0x%llx\n",
1639 len, ack->size, (unsigned long long)ack->mask,
1640 (unsigned long long)ack->memory_types);
1641 return true;
1642 }
1643
send_coredump_ack_types(int fd,const struct coredump_req * req,__u64 mask,__u64 memory_types,size_t size_ack)1644 bool send_coredump_ack_types(int fd, const struct coredump_req *req,
1645 __u64 mask, __u64 memory_types, size_t size_ack)
1646 {
1647 struct coredump_ack ack = {
1648 .mask = mask,
1649 .memory_types = memory_types,
1650 };
1651
1652 if (!size_ack)
1653 size_ack = sizeof(struct coredump_ack) < req->size_ack ?
1654 sizeof(struct coredump_ack) :
1655 req->size_ack;
1656 ack.size = size_ack;
1657 return send_coredump_ack_bytes(fd, &ack, size_ack);
1658 }
1659
send_coredump_ack(int fd,const struct coredump_req * req,__u64 mask,size_t size_ack)1660 bool send_coredump_ack(int fd, const struct coredump_req *req,
1661 __u64 mask, size_t size_ack)
1662 {
1663 return send_coredump_ack_types(fd, req, mask, 0, size_ack);
1664 }
1665
1666 /* Every option the kernel is expected to advertise in coredump_req->mask. */
1667 #define TEST_REQ_MASK_ALL \
1668 (COREDUMP_KERNEL | COREDUMP_USERSPACE | \
1669 COREDUMP_REJECT | COREDUMP_WAIT | \
1670 COREDUMP_RECORDS | COREDUMP_SPARSE | COREDUMP_MEMORY_TYPES)
1671
check_coredump_req(const struct coredump_req * req)1672 bool check_coredump_req(const struct coredump_req *req)
1673 {
1674 if (req->size != COREDUMP_REQ_SIZE_VER1) {
1675 fprintf(stderr, "%s: size %u, expected %d\n",
1676 __func__, req->size, COREDUMP_REQ_SIZE_VER1);
1677 return false;
1678 }
1679 if (req->size_ack != COREDUMP_ACK_SIZE_VER1) {
1680 fprintf(stderr, "%s: size_ack %u, expected %d\n",
1681 __func__, req->size_ack, COREDUMP_ACK_SIZE_VER1);
1682 return false;
1683 }
1684 if (req->mask != TEST_REQ_MASK_ALL) {
1685 fprintf(stderr, "%s: mask 0x%llx, expected 0x%llx\n",
1686 __func__, (unsigned long long)req->mask,
1687 (unsigned long long)TEST_REQ_MASK_ALL);
1688 return false;
1689 }
1690 if (req->memory_types_mask != TEST_MEMORY_ALL) {
1691 fprintf(stderr, "%s: memory_types_mask 0x%llx, expected 0x%llx\n",
1692 __func__, (unsigned long long)req->memory_types_mask,
1693 (unsigned long long)TEST_MEMORY_ALL);
1694 return false;
1695 }
1696 return true;
1697 }
1698
open_coredump_tmpfile(int fd_tmpfs_detached)1699 int open_coredump_tmpfile(int fd_tmpfs_detached)
1700 {
1701 return openat(fd_tmpfs_detached, ".", O_TMPFILE | O_RDWR | O_EXCL, 0600);
1702 }
1703
process_coredump_worker(int fd_coredump,int fd_peer_pidfd,int fd_core_file)1704 void process_coredump_worker(int fd_coredump, int fd_peer_pidfd, int fd_core_file)
1705 {
1706 int epfd = -1;
1707 int exit_code = EXIT_FAILURE;
1708 struct epoll_event ev;
1709 int flags;
1710
1711 /* Set socket to non-blocking mode for edge-triggered epoll */
1712 flags = fcntl(fd_coredump, F_GETFL, 0);
1713 if (flags < 0) {
1714 fprintf(stderr, "Worker: fcntl(F_GETFL) failed: %m\n");
1715 goto out;
1716 }
1717 if (fcntl(fd_coredump, F_SETFL, flags | O_NONBLOCK) < 0) {
1718 fprintf(stderr, "Worker: fcntl(F_SETFL, O_NONBLOCK) failed: %m\n");
1719 goto out;
1720 }
1721
1722 epfd = epoll_create1(0);
1723 if (epfd < 0) {
1724 fprintf(stderr, "Worker: epoll_create1() failed: %m\n");
1725 goto out;
1726 }
1727
1728 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
1729 ev.data.fd = fd_coredump;
1730 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd_coredump, &ev) < 0) {
1731 fprintf(stderr, "Worker: epoll_ctl(EPOLL_CTL_ADD) failed: %m\n");
1732 goto out;
1733 }
1734
1735 for (;;) {
1736 struct epoll_event events[1];
1737 int n = epoll_wait(epfd, events, 1, -1);
1738 if (n < 0) {
1739 fprintf(stderr, "Worker: epoll_wait() failed: %m\n");
1740 break;
1741 }
1742
1743 if (events[0].events & (EPOLLIN | EPOLLRDHUP)) {
1744 for (;;) {
1745 char buffer[4096];
1746 ssize_t bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1747 if (bytes_read < 0) {
1748 if (errno == EAGAIN || errno == EWOULDBLOCK)
1749 break;
1750 fprintf(stderr, "Worker: read() failed: %m\n");
1751 goto out;
1752 }
1753 if (bytes_read == 0)
1754 goto done;
1755 ssize_t bytes_write = write(fd_core_file, buffer, bytes_read);
1756 if (bytes_write != bytes_read) {
1757 if (bytes_write < 0 && errno == ENOSPC)
1758 continue;
1759 fprintf(stderr, "Worker: write() failed (read=%zd, write=%zd): %m\n",
1760 bytes_read, bytes_write);
1761 goto out;
1762 }
1763 }
1764 }
1765 }
1766
1767 done:
1768 exit_code = EXIT_SUCCESS;
1769 fprintf(stderr, "Worker: completed successfully\n");
1770 out:
1771 if (epfd >= 0)
1772 close(epfd);
1773 if (fd_core_file >= 0)
1774 close(fd_core_file);
1775 if (fd_peer_pidfd >= 0)
1776 close(fd_peer_pidfd);
1777 if (fd_coredump >= 0)
1778 close(fd_coredump);
1779 _exit(exit_code);
1780 }
1781
1782 /*
1783 * TIF_NOTIFY_SIGNAL coredump helpers.
1784 *
1785 * __dump_emit() takes anything short of a full write as the end of the
1786 * dump, so every emit that blocks on a full transport can lose the rest
1787 * of it. The NT_FILE note is the one emit that is certain to block,
1788 * because it is the only one larger than the transport, so these helpers
1789 * build a note large enough for that and then raise TIF_NOTIFY_SIGNAL on
1790 * the dumping task while that write is in flight.
1791 */
1792
io_uring_setup_raw(unsigned int entries,struct io_uring_params * p)1793 static int io_uring_setup_raw(unsigned int entries, struct io_uring_params *p)
1794 {
1795 return syscall(__NR_io_uring_setup, entries, p);
1796 }
1797
1798 /* io_uring reads poll32_events back through swahw32() on big endian. */
notify_poll_mask(__u32 events)1799 static __u32 notify_poll_mask(__u32 events)
1800 {
1801 #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
1802 return __swahw32(events);
1803 #else
1804 return events;
1805 #endif
1806 }
1807
coredump_io_uring_available(void)1808 bool coredump_io_uring_available(void)
1809 {
1810 struct io_uring_params p = {};
1811 int fd;
1812
1813 fd = io_uring_setup_raw(1, &p);
1814 if (fd < 0)
1815 return false;
1816 close(fd);
1817 return true;
1818 }
1819
1820 /*
1821 * Arm a poll on @fd. io_uring leaves ctx->notify_method at TWA_SIGNAL
1822 * unless the ring asks for SQPOLL or COOP_TASKRUN, so the completion runs
1823 * set_notify_signal() against the task that submitted it. That is us, and
1824 * we are about to become the coredumping task.
1825 */
arm_poll_notify(int trigger_fd)1826 static int arm_poll_notify(int trigger_fd)
1827 {
1828 struct io_uring_params p = {};
1829 unsigned int *sq_tail, *sq_array;
1830 struct io_uring_sqe *sqes;
1831 size_t sqring_sz;
1832 void *sq;
1833 int ring;
1834
1835 ring = io_uring_setup_raw(8, &p);
1836 if (ring < 0)
1837 return -1;
1838
1839 sqring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned int);
1840 sq = mmap(NULL, sqring_sz, PROT_READ | PROT_WRITE,
1841 MAP_SHARED | MAP_POPULATE, ring, IORING_OFF_SQ_RING);
1842 if (sq == MAP_FAILED)
1843 return -1;
1844
1845 sqes = mmap(NULL, p.sq_entries * sizeof(*sqes), PROT_READ | PROT_WRITE,
1846 MAP_SHARED | MAP_POPULATE, ring, IORING_OFF_SQES);
1847 if (sqes == MAP_FAILED)
1848 return -1;
1849
1850 sq_tail = (unsigned int *)((char *)sq + p.sq_off.tail);
1851 sq_array = (unsigned int *)((char *)sq + p.sq_off.array);
1852
1853 memset(&sqes[0], 0, sizeof(sqes[0]));
1854 sqes[0].opcode = IORING_OP_POLL_ADD;
1855 sqes[0].fd = trigger_fd;
1856 sqes[0].poll32_events = notify_poll_mask(POLLIN);
1857
1858 sq_array[0] = 0;
1859 __atomic_store_n(sq_tail, 1, __ATOMIC_RELEASE);
1860
1861 if (syscall(__NR_io_uring_enter, ring, 1, 0, 0, NULL, 0) < 0)
1862 return -1;
1863
1864 /* Deliberately leaked, we are about to crash. */
1865 return 0;
1866 }
1867
1868 /*
1869 * Adjacent mappings with identical flags and contiguous file offsets are
1870 * merged into one VMA, which would collapse NT_FILE back to nothing, so
1871 * alternate the protection to keep every mapping an entry of its own.
1872 * Not PROT_EXEC, /tmp is often mounted noexec. Nothing is ever written
1873 * through these so they get no anon_vma and stay out of the dump itself.
1874 */
make_file_mappings(void)1875 static int make_file_mappings(void)
1876 {
1877 long pgsz = sysconf(_SC_PAGESIZE);
1878 int fd, i;
1879
1880 fd = open(NOTIFY_SIGNAL_MAPFILE,
1881 O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
1882 if (fd < 0)
1883 return 0;
1884 if (ftruncate(fd, (off_t)NOTIFY_SIGNAL_MAP_COUNT * pgsz)) {
1885 close(fd);
1886 return 0;
1887 }
1888
1889 for (i = 0; i < NOTIFY_SIGNAL_MAP_COUNT; i++) {
1890 int prot = (i & 1) ? PROT_READ : (PROT_READ | PROT_WRITE);
1891
1892 if (mmap(NULL, pgsz, prot, MAP_PRIVATE, fd,
1893 (off_t)i * pgsz) == MAP_FAILED)
1894 break;
1895 }
1896 close(fd);
1897 return i;
1898 }
1899
crashing_child_notify_signal(void)1900 void crashing_child_notify_signal(void)
1901 {
1902 long pgsz = sysconf(_SC_PAGESIZE);
1903 unsigned char *p;
1904 int trigger_fd;
1905 unsigned long off;
1906
1907 /* Open the read side first so the reader's open() cannot block. */
1908 trigger_fd = open(NOTIFY_SIGNAL_TRIGGER, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1909
1910 /* Exit rather than crash: a dump without the poll armed proves nothing. */
1911 if (trigger_fd < 0)
1912 _exit(EXIT_FAILURE);
1913
1914 if (make_file_mappings() < NOTIFY_SIGNAL_MAP_COUNT)
1915 _exit(EXIT_FAILURE);
1916
1917 p = mmap(NULL, NOTIFY_SIGNAL_ANON_BYTES, PROT_READ | PROT_WRITE,
1918 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1919 if (p == MAP_FAILED)
1920 _exit(EXIT_FAILURE);
1921 for (off = 0; off < NOTIFY_SIGNAL_ANON_BYTES; off += pgsz)
1922 p[off] = 1;
1923
1924 if (arm_poll_notify(trigger_fd))
1925 _exit(EXIT_FAILURE);
1926
1927 /* crash on purpose */
1928 *(volatile int *)NULL = 0;
1929 _exit(EXIT_FAILURE);
1930 }
1931
pull_trigger(void)1932 static int pull_trigger(void)
1933 {
1934 int fd;
1935
1936 fd = open(NOTIFY_SIGNAL_TRIGGER, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
1937 if (fd < 0) {
1938 fprintf(stderr, "%s: open failed: %m\n", __func__);
1939 return -1;
1940 }
1941 if (write(fd, "x", 1) != 1) {
1942 fprintf(stderr, "%s: write failed: %m\n", __func__);
1943 close(fd);
1944 return -1;
1945 }
1946 close(fd);
1947 return 0;
1948 }
1949
1950 /*
1951 * phdr[0] is the PT_NOTE entry: elf_core_dump() emits it right after the
1952 * ELF header. Its p_offset is where the notes begin.
1953 */
note_offset(const unsigned char * hdr)1954 static long long note_offset(const unsigned char *hdr)
1955 {
1956 ElfW(Phdr) ph;
1957 ElfW(Ehdr) eh;
1958
1959 memcpy(&eh, hdr, sizeof(eh));
1960 if (memcmp(eh.e_ident, ELFMAG, SELFMAG) || eh.e_type != ET_CORE)
1961 return -1;
1962 memcpy(&ph, hdr + sizeof(eh), sizeof(ph));
1963 if (ph.p_type != PT_NOTE)
1964 return -1;
1965 return (long long)ph.p_offset;
1966 }
1967
1968 /*
1969 * Drain a coredump off @fd, counting what arrives. Once the notes have
1970 * started the kernel is inside the one big note write, so poke the fifo
1971 * the crashing task is polling and stop reading, which keeps the
1972 * transport full and the write blocked with a partial count when the
1973 * wakeup lands. Then carry on to end of file.
1974 *
1975 * What arrives is written to @fd_out when that is not negative.
1976 * Returns the number of bytes received, or -1. Failing to trip the fifo
1977 * is an error too: a dump that was never interrupted proves nothing.
1978 */
recv_coredump_notify_signal(int fd,int fd_out,bool arm)1979 ssize_t recv_coredump_notify_signal(int fd, int fd_out, bool arm)
1980 {
1981 unsigned char hdr[sizeof(ElfW(Ehdr)) + sizeof(ElfW(Phdr))];
1982 static char buf[64 << 10];
1983 long pgsz = sysconf(_SC_PAGESIZE);
1984 long long note_off = 0;
1985 size_t hdrlen = 0;
1986 ssize_t total = 0;
1987 bool armed = false;
1988
1989 for (;;) {
1990 ssize_t n = read(fd, buf, sizeof(buf));
1991
1992 if (n < 0) {
1993 if (errno == EINTR)
1994 continue;
1995 return -1;
1996 }
1997 if (n == 0)
1998 break;
1999 if (fd_out >= 0 && write(fd_out, buf, n) != n)
2000 return -1;
2001
2002 if (hdrlen < sizeof(hdr)) {
2003 size_t want = sizeof(hdr) - hdrlen;
2004
2005 if (want > (size_t)n)
2006 want = (size_t)n;
2007 memcpy(hdr + hdrlen, buf, want);
2008 hdrlen += want;
2009 if (hdrlen == sizeof(hdr))
2010 note_off = note_offset(hdr);
2011 }
2012
2013 total += n;
2014
2015 if (arm && !armed && note_off > 0 &&
2016 total > note_off + (long long)pgsz) {
2017 if (pull_trigger())
2018 return -1;
2019 armed = true;
2020 usleep(NOTIFY_SIGNAL_STALL_US);
2021 continue;
2022 }
2023 }
2024
2025 if (arm && !armed)
2026 return -1;
2027
2028 return total;
2029 }
2030
2031 /*
2032 * How large the dump was meant to be. The ELF header and the program
2033 * headers are the first thing emitted, so even a truncated dump says how
2034 * far it should have run: the end is max(p_offset + p_filesz).
2035 *
2036 * That end is exact even when the last segment ends in a hole:
2037 * coredump_write() flushes the pending cprm->to_skip with a final one
2038 * byte emit and __dump_skip() writes zeroes for transports that cannot
2039 * seek, so a whole dump carries every byte the headers promise.
2040 */
coredump_expected_size(const char * path)2041 long long coredump_expected_size(const char *path)
2042 {
2043 ElfW(Phdr) *phdr = NULL;
2044 long long expected = 0;
2045 unsigned int nphdr, i;
2046 ElfW(Ehdr) eh;
2047 int fd;
2048
2049 fd = open(path, O_RDONLY | O_CLOEXEC);
2050 if (fd < 0)
2051 return -1;
2052 if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
2053 goto err;
2054 if (memcmp(eh.e_ident, ELFMAG, SELFMAG) || eh.e_type != ET_CORE)
2055 goto err;
2056 if (!eh.e_phnum || eh.e_phentsize != sizeof(*phdr))
2057 goto err;
2058
2059 nphdr = eh.e_phnum;
2060 phdr = calloc(nphdr, sizeof(*phdr));
2061 if (!phdr)
2062 goto err;
2063 if (pread(fd, phdr, (size_t)nphdr * sizeof(*phdr), (off_t)eh.e_phoff) !=
2064 (ssize_t)((size_t)nphdr * sizeof(*phdr)))
2065 goto err;
2066
2067 for (i = 0; i < nphdr; i++) {
2068 long long end = (long long)phdr[i].p_offset +
2069 (long long)phdr[i].p_filesz;
2070 if (end > expected)
2071 expected = end;
2072 }
2073
2074 free(phdr);
2075 close(fd);
2076 return expected;
2077 err:
2078 free(phdr);
2079 close(fd);
2080 return -1;
2081 }
2082