Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3#include <assert.h>
4#include <fcntl.h>
5#include <inttypes.h>
6#include <libgen.h>
7#include <limits.h>
8#include <linux/coredump.h>
9#include <linux/fs.h>
10#include <linux/limits.h>
11#include <pthread.h>
12#include <string.h>
13#include <sys/mount.h>
14#include <poll.h>
15#include <sys/epoll.h>
16#include <sys/resource.h>
17#include <sys/stat.h>
18#include <sys/socket.h>
19#include <sys/un.h>
20#include <unistd.h>
21
22#include "../kselftest_harness.h"
23#include "../filesystems/wrappers.h"
24#include "../pidfd/pidfd.h"
25
26#define STACKDUMP_FILE "stack_values"
27#define STACKDUMP_SCRIPT "stackdump"
28#define NUM_THREAD_SPAWN 128
29
30#ifndef PAGE_SIZE
31#define PAGE_SIZE 4096
32#endif
33
34static void *do_nothing(void *)
35{
36 while (1)
37 pause();
38
39 return NULL;
40}
41
42static void crashing_child(void)
43{
44 pthread_t thread;
45 int i;
46
47 for (i = 0; i < NUM_THREAD_SPAWN; ++i)
48 pthread_create(&thread, NULL, do_nothing, NULL);
49
50 /* crash on purpose */
51 i = *(int *)NULL;
52}
53
54FIXTURE(coredump)
55{
56 char original_core_pattern[256];
57 pid_t pid_coredump_server;
58 int fd_tmpfs_detached;
59};
60
61static int create_detached_tmpfs(void)
62{
63 int fd_context, fd_tmpfs;
64
65 fd_context = sys_fsopen("tmpfs", 0);
66 if (fd_context < 0)
67 return -1;
68
69 if (sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0)
70 return -1;
71
72 fd_tmpfs = sys_fsmount(fd_context, 0, 0);
73 close(fd_context);
74 return fd_tmpfs;
75}
76
77FIXTURE_SETUP(coredump)
78{
79 FILE *file;
80 int ret;
81
82 self->pid_coredump_server = -ESRCH;
83 self->fd_tmpfs_detached = -1;
84 file = fopen("/proc/sys/kernel/core_pattern", "r");
85 ASSERT_NE(NULL, file);
86
87 ret = fread(self->original_core_pattern, 1, sizeof(self->original_core_pattern), file);
88 ASSERT_TRUE(ret || feof(file));
89 ASSERT_LT(ret, sizeof(self->original_core_pattern));
90
91 self->original_core_pattern[ret] = '\0';
92 self->fd_tmpfs_detached = create_detached_tmpfs();
93 ASSERT_GE(self->fd_tmpfs_detached, 0);
94
95 ret = fclose(file);
96 ASSERT_EQ(0, ret);
97}
98
99FIXTURE_TEARDOWN(coredump)
100{
101 const char *reason;
102 FILE *file;
103 int ret, status;
104
105 unlink(STACKDUMP_FILE);
106
107 if (self->pid_coredump_server > 0) {
108 kill(self->pid_coredump_server, SIGTERM);
109 waitpid(self->pid_coredump_server, &status, 0);
110 }
111 unlink("/tmp/coredump.file");
112 unlink("/tmp/coredump.socket");
113
114 file = fopen("/proc/sys/kernel/core_pattern", "w");
115 if (!file) {
116 reason = "Unable to open core_pattern";
117 goto fail;
118 }
119
120 ret = fprintf(file, "%s", self->original_core_pattern);
121 if (ret < 0) {
122 reason = "Unable to write to core_pattern";
123 goto fail;
124 }
125
126 ret = fclose(file);
127 if (ret) {
128 reason = "Unable to close core_pattern";
129 goto fail;
130 }
131
132 if (self->fd_tmpfs_detached >= 0) {
133 ret = close(self->fd_tmpfs_detached);
134 if (ret < 0) {
135 reason = "Unable to close detached tmpfs";
136 goto fail;
137 }
138 self->fd_tmpfs_detached = -1;
139 }
140
141 return;
142fail:
143 /* This should never happen */
144 fprintf(stderr, "Failed to cleanup stackdump test: %s\n", reason);
145}
146
147TEST_F_TIMEOUT(coredump, stackdump, 120)
148{
149 unsigned long long stack;
150 char *test_dir, *line;
151 size_t line_length;
152 char buf[PAGE_SIZE];
153 int ret, i, status;
154 FILE *file;
155 pid_t pid;
156
157 /*
158 * Step 1: Setup core_pattern so that the stackdump script is executed when the child
159 * process crashes
160 */
161 ret = readlink("/proc/self/exe", buf, sizeof(buf));
162 ASSERT_NE(-1, ret);
163 ASSERT_LT(ret, sizeof(buf));
164 buf[ret] = '\0';
165
166 test_dir = dirname(buf);
167
168 file = fopen("/proc/sys/kernel/core_pattern", "w");
169 ASSERT_NE(NULL, file);
170
171 ret = fprintf(file, "|%1$s/%2$s %%P %1$s/%3$s", test_dir, STACKDUMP_SCRIPT, STACKDUMP_FILE);
172 ASSERT_LT(0, ret);
173
174 ret = fclose(file);
175 ASSERT_EQ(0, ret);
176
177 /* Step 2: Create a process who spawns some threads then crashes */
178 pid = fork();
179 ASSERT_TRUE(pid >= 0);
180 if (pid == 0)
181 crashing_child();
182
183 /*
184 * Step 3: Wait for the stackdump script to write the stack pointers to the stackdump file
185 */
186 waitpid(pid, &status, 0);
187 ASSERT_TRUE(WIFSIGNALED(status));
188 ASSERT_TRUE(WCOREDUMP(status));
189
190 for (i = 0; i < 10; ++i) {
191 file = fopen(STACKDUMP_FILE, "r");
192 if (file)
193 break;
194 sleep(1);
195 }
196 ASSERT_NE(file, NULL);
197
198 /* Step 4: Make sure all stack pointer values are non-zero */
199 line = NULL;
200 for (i = 0; -1 != getline(&line, &line_length, file); ++i) {
201 stack = strtoull(line, NULL, 10);
202 ASSERT_NE(stack, 0);
203 }
204 free(line);
205
206 ASSERT_EQ(i, 1 + NUM_THREAD_SPAWN);
207
208 fclose(file);
209}
210
211static int create_and_listen_unix_socket(const char *path)
212{
213 struct sockaddr_un addr = {
214 .sun_family = AF_UNIX,
215 };
216 assert(strlen(path) < sizeof(addr.sun_path) - 1);
217 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
218 size_t addr_len =
219 offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1;
220 int fd, ret;
221
222 fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
223 if (fd < 0)
224 goto out;
225
226 ret = bind(fd, (const struct sockaddr *)&addr, addr_len);
227 if (ret < 0)
228 goto out;
229
230 ret = listen(fd, 128);
231 if (ret < 0)
232 goto out;
233
234 return fd;
235
236out:
237 if (fd >= 0)
238 close(fd);
239 return -1;
240}
241
242static bool set_core_pattern(const char *pattern)
243{
244 int fd;
245 ssize_t ret;
246
247 fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC);
248 if (fd < 0)
249 return false;
250
251 ret = write(fd, pattern, strlen(pattern));
252 close(fd);
253 if (ret < 0)
254 return false;
255
256 fprintf(stderr, "Set core_pattern to '%s' | %zu == %zu\n", pattern, ret, strlen(pattern));
257 return ret == strlen(pattern);
258}
259
260static int get_peer_pidfd(int fd)
261{
262 int fd_peer_pidfd;
263 socklen_t fd_peer_pidfd_len = sizeof(fd_peer_pidfd);
264 int ret = getsockopt(fd, SOL_SOCKET, SO_PEERPIDFD, &fd_peer_pidfd,
265 &fd_peer_pidfd_len);
266 if (ret < 0) {
267 fprintf(stderr, "%m - Failed to retrieve peer pidfd for coredump socket connection\n");
268 return -1;
269 }
270 return fd_peer_pidfd;
271}
272
273static bool get_pidfd_info(int fd_peer_pidfd, struct pidfd_info *info)
274{
275 memset(info, 0, sizeof(*info));
276 info->mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
277 return ioctl(fd_peer_pidfd, PIDFD_GET_INFO, info) == 0;
278}
279
280static void
281wait_and_check_coredump_server(pid_t pid_coredump_server,
282 struct __test_metadata *const _metadata,
283 FIXTURE_DATA(coredump)* self)
284{
285 int status;
286 waitpid(pid_coredump_server, &status, 0);
287 self->pid_coredump_server = -ESRCH;
288 ASSERT_TRUE(WIFEXITED(status));
289 ASSERT_EQ(WEXITSTATUS(status), 0);
290}
291
292TEST_F(coredump, socket)
293{
294 int pidfd, ret, status;
295 pid_t pid, pid_coredump_server;
296 struct stat st;
297 struct pidfd_info info = {};
298 int ipc_sockets[2];
299 char c;
300
301 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
302
303 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
304 ASSERT_EQ(ret, 0);
305
306 pid_coredump_server = fork();
307 ASSERT_GE(pid_coredump_server, 0);
308 if (pid_coredump_server == 0) {
309 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
310 int exit_code = EXIT_FAILURE;
311
312 close(ipc_sockets[0]);
313
314 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
315 if (fd_server < 0)
316 goto out;
317
318 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
319 goto out;
320
321 close(ipc_sockets[1]);
322
323 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
324 if (fd_coredump < 0)
325 goto out;
326
327 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
328 if (fd_peer_pidfd < 0)
329 goto out;
330
331 if (!get_pidfd_info(fd_peer_pidfd, &info))
332 goto out;
333
334 if (!(info.mask & PIDFD_INFO_COREDUMP))
335 goto out;
336
337 if (!(info.coredump_mask & PIDFD_COREDUMPED))
338 goto out;
339
340 fd_core_file = creat("/tmp/coredump.file", 0644);
341 if (fd_core_file < 0)
342 goto out;
343
344 for (;;) {
345 char buffer[4096];
346 ssize_t bytes_read, bytes_write;
347
348 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
349 if (bytes_read < 0)
350 goto out;
351
352 if (bytes_read == 0)
353 break;
354
355 bytes_write = write(fd_core_file, buffer, bytes_read);
356 if (bytes_read != bytes_write)
357 goto out;
358 }
359
360 exit_code = EXIT_SUCCESS;
361out:
362 if (fd_core_file >= 0)
363 close(fd_core_file);
364 if (fd_peer_pidfd >= 0)
365 close(fd_peer_pidfd);
366 if (fd_coredump >= 0)
367 close(fd_coredump);
368 if (fd_server >= 0)
369 close(fd_server);
370 _exit(exit_code);
371 }
372 self->pid_coredump_server = pid_coredump_server;
373
374 EXPECT_EQ(close(ipc_sockets[1]), 0);
375 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
376 EXPECT_EQ(close(ipc_sockets[0]), 0);
377
378 pid = fork();
379 ASSERT_GE(pid, 0);
380 if (pid == 0)
381 crashing_child();
382
383 pidfd = sys_pidfd_open(pid, 0);
384 ASSERT_GE(pidfd, 0);
385
386 waitpid(pid, &status, 0);
387 ASSERT_TRUE(WIFSIGNALED(status));
388 ASSERT_TRUE(WCOREDUMP(status));
389
390 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
391 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
392 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
393
394 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
395
396 ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
397 ASSERT_GT(st.st_size, 0);
398 system("file /tmp/coredump.file");
399}
400
401TEST_F(coredump, socket_detect_userspace_client)
402{
403 int pidfd, ret, status;
404 pid_t pid, pid_coredump_server;
405 struct stat st;
406 struct pidfd_info info = {};
407 int ipc_sockets[2];
408 char c;
409
410 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
411
412 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
413 ASSERT_EQ(ret, 0);
414
415 pid_coredump_server = fork();
416 ASSERT_GE(pid_coredump_server, 0);
417 if (pid_coredump_server == 0) {
418 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
419 int exit_code = EXIT_FAILURE;
420
421 close(ipc_sockets[0]);
422
423 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
424 if (fd_server < 0)
425 goto out;
426
427 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
428 goto out;
429
430 close(ipc_sockets[1]);
431
432 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
433 if (fd_coredump < 0)
434 goto out;
435
436 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
437 if (fd_peer_pidfd < 0)
438 goto out;
439
440 if (!get_pidfd_info(fd_peer_pidfd, &info))
441 goto out;
442
443 if (!(info.mask & PIDFD_INFO_COREDUMP))
444 goto out;
445
446 if (info.coredump_mask & PIDFD_COREDUMPED)
447 goto out;
448
449 if (read(fd_coredump, &c, 1) < 1)
450 goto out;
451
452 exit_code = EXIT_SUCCESS;
453out:
454 if (fd_peer_pidfd >= 0)
455 close(fd_peer_pidfd);
456 if (fd_coredump >= 0)
457 close(fd_coredump);
458 if (fd_server >= 0)
459 close(fd_server);
460 _exit(exit_code);
461 }
462 self->pid_coredump_server = pid_coredump_server;
463
464 EXPECT_EQ(close(ipc_sockets[1]), 0);
465 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
466 EXPECT_EQ(close(ipc_sockets[0]), 0);
467
468 pid = fork();
469 ASSERT_GE(pid, 0);
470 if (pid == 0) {
471 int fd_socket;
472 ssize_t ret;
473 const struct sockaddr_un coredump_sk = {
474 .sun_family = AF_UNIX,
475 .sun_path = "/tmp/coredump.socket",
476 };
477 size_t coredump_sk_len =
478 offsetof(struct sockaddr_un, sun_path) +
479 sizeof("/tmp/coredump.socket");
480
481 fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
482 if (fd_socket < 0)
483 _exit(EXIT_FAILURE);
484
485 ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
486 if (ret < 0)
487 _exit(EXIT_FAILURE);
488
489 close(fd_socket);
490 _exit(EXIT_SUCCESS);
491 }
492
493 pidfd = sys_pidfd_open(pid, 0);
494 ASSERT_GE(pidfd, 0);
495
496 waitpid(pid, &status, 0);
497 ASSERT_TRUE(WIFEXITED(status));
498 ASSERT_EQ(WEXITSTATUS(status), 0);
499
500 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
501 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
502 ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0);
503
504 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
505
506 ASSERT_NE(stat("/tmp/coredump.file", &st), 0);
507 ASSERT_EQ(errno, ENOENT);
508}
509
510TEST_F(coredump, socket_enoent)
511{
512 int pidfd, status;
513 pid_t pid;
514
515 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
516
517 pid = fork();
518 ASSERT_GE(pid, 0);
519 if (pid == 0)
520 crashing_child();
521
522 pidfd = sys_pidfd_open(pid, 0);
523 ASSERT_GE(pidfd, 0);
524
525 waitpid(pid, &status, 0);
526 ASSERT_TRUE(WIFSIGNALED(status));
527 ASSERT_FALSE(WCOREDUMP(status));
528}
529
530TEST_F(coredump, socket_no_listener)
531{
532 int pidfd, ret, status;
533 pid_t pid, pid_coredump_server;
534 int ipc_sockets[2];
535 char c;
536 const struct sockaddr_un coredump_sk = {
537 .sun_family = AF_UNIX,
538 .sun_path = "/tmp/coredump.socket",
539 };
540 size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) +
541 sizeof("/tmp/coredump.socket");
542
543 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
544
545 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
546 ASSERT_EQ(ret, 0);
547
548 pid_coredump_server = fork();
549 ASSERT_GE(pid_coredump_server, 0);
550 if (pid_coredump_server == 0) {
551 int fd_server = -1;
552 int exit_code = EXIT_FAILURE;
553
554 close(ipc_sockets[0]);
555
556 fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
557 if (fd_server < 0)
558 goto out;
559
560 ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
561 if (ret < 0)
562 goto out;
563
564 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
565 goto out;
566
567 exit_code = EXIT_SUCCESS;
568out:
569 if (fd_server >= 0)
570 close(fd_server);
571 close(ipc_sockets[1]);
572 _exit(exit_code);
573 }
574 self->pid_coredump_server = pid_coredump_server;
575
576 EXPECT_EQ(close(ipc_sockets[1]), 0);
577 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
578 EXPECT_EQ(close(ipc_sockets[0]), 0);
579
580 pid = fork();
581 ASSERT_GE(pid, 0);
582 if (pid == 0)
583 crashing_child();
584
585 pidfd = sys_pidfd_open(pid, 0);
586 ASSERT_GE(pidfd, 0);
587
588 waitpid(pid, &status, 0);
589 ASSERT_TRUE(WIFSIGNALED(status));
590 ASSERT_FALSE(WCOREDUMP(status));
591
592 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
593}
594
595static ssize_t recv_marker(int fd)
596{
597 enum coredump_mark mark = COREDUMP_MARK_REQACK;
598 ssize_t ret;
599
600 ret = recv(fd, &mark, sizeof(mark), MSG_WAITALL);
601 if (ret != sizeof(mark))
602 return -1;
603
604 switch (mark) {
605 case COREDUMP_MARK_REQACK:
606 fprintf(stderr, "Received marker: ReqAck\n");
607 return COREDUMP_MARK_REQACK;
608 case COREDUMP_MARK_MINSIZE:
609 fprintf(stderr, "Received marker: MinSize\n");
610 return COREDUMP_MARK_MINSIZE;
611 case COREDUMP_MARK_MAXSIZE:
612 fprintf(stderr, "Received marker: MaxSize\n");
613 return COREDUMP_MARK_MAXSIZE;
614 case COREDUMP_MARK_UNSUPPORTED:
615 fprintf(stderr, "Received marker: Unsupported\n");
616 return COREDUMP_MARK_UNSUPPORTED;
617 case COREDUMP_MARK_CONFLICTING:
618 fprintf(stderr, "Received marker: Conflicting\n");
619 return COREDUMP_MARK_CONFLICTING;
620 default:
621 fprintf(stderr, "Received unknown marker: %u\n", mark);
622 break;
623 }
624 return -1;
625}
626
627static bool read_marker(int fd, enum coredump_mark mark)
628{
629 ssize_t ret;
630
631 ret = recv_marker(fd);
632 if (ret < 0)
633 return false;
634 return ret == mark;
635}
636
637static bool read_coredump_req(int fd, struct coredump_req *req)
638{
639 ssize_t ret;
640 size_t field_size, user_size, ack_size, kernel_size, remaining_size;
641
642 memset(req, 0, sizeof(*req));
643 field_size = sizeof(req->size);
644
645 /* Peek the size of the coredump request. */
646 ret = recv(fd, req, field_size, MSG_PEEK | MSG_WAITALL);
647 if (ret != field_size)
648 return false;
649 kernel_size = req->size;
650
651 if (kernel_size < COREDUMP_ACK_SIZE_VER0)
652 return false;
653 if (kernel_size >= PAGE_SIZE)
654 return false;
655
656 /* Use the minimum of user and kernel size to read the full request. */
657 user_size = sizeof(struct coredump_req);
658 ack_size = user_size < kernel_size ? user_size : kernel_size;
659 ret = recv(fd, req, ack_size, MSG_WAITALL);
660 if (ret != ack_size)
661 return false;
662
663 fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n",
664 req->size, (unsigned long long)req->mask);
665
666 if (user_size > kernel_size)
667 remaining_size = user_size - kernel_size;
668 else
669 remaining_size = kernel_size - user_size;
670
671 if (PAGE_SIZE <= remaining_size)
672 return false;
673
674 /*
675 * Discard any additional data if the kernel's request was larger than
676 * what we knew about or cared about.
677 */
678 if (remaining_size) {
679 char buffer[PAGE_SIZE];
680
681 ret = recv(fd, buffer, sizeof(buffer), MSG_WAITALL);
682 if (ret != remaining_size)
683 return false;
684 fprintf(stderr, "Discarded %zu bytes of data after coredump request\n", remaining_size);
685 }
686
687 return true;
688}
689
690static bool send_coredump_ack(int fd, const struct coredump_req *req,
691 __u64 mask, size_t size_ack)
692{
693 ssize_t ret;
694 /*
695 * Wrap struct coredump_ack in a larger struct so we can
696 * simulate sending to much data to the kernel.
697 */
698 struct large_ack_for_size_testing {
699 struct coredump_ack ack;
700 char buffer[PAGE_SIZE];
701 } large_ack = {};
702
703 if (!size_ack)
704 size_ack = sizeof(struct coredump_ack) < req->size_ack ?
705 sizeof(struct coredump_ack) :
706 req->size_ack;
707 large_ack.ack.mask = mask;
708 large_ack.ack.size = size_ack;
709 ret = send(fd, &large_ack, size_ack, MSG_NOSIGNAL);
710 if (ret != size_ack)
711 return false;
712
713 fprintf(stderr, "Sent coredump ack with size %zu and mask 0x%llx\n",
714 size_ack, (unsigned long long)mask);
715 return true;
716}
717
718static bool check_coredump_req(const struct coredump_req *req, size_t min_size,
719 __u64 required_mask)
720{
721 if (req->size < min_size)
722 return false;
723 if ((req->mask & required_mask) != required_mask)
724 return false;
725 if (req->mask & ~required_mask)
726 return false;
727 return true;
728}
729
730TEST_F(coredump, socket_request_kernel)
731{
732 int pidfd, ret, status;
733 pid_t pid, pid_coredump_server;
734 struct stat st;
735 struct pidfd_info info = {};
736 int ipc_sockets[2];
737 char c;
738
739 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
740
741 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
742 ASSERT_EQ(ret, 0);
743
744 pid_coredump_server = fork();
745 ASSERT_GE(pid_coredump_server, 0);
746 if (pid_coredump_server == 0) {
747 struct coredump_req req = {};
748 int fd_server = -1, fd_coredump = -1, fd_core_file = -1, fd_peer_pidfd = -1;
749 int exit_code = EXIT_FAILURE;
750
751 close(ipc_sockets[0]);
752
753 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
754 if (fd_server < 0)
755 goto out;
756
757 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
758 goto out;
759
760 close(ipc_sockets[1]);
761
762 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
763 if (fd_coredump < 0)
764 goto out;
765
766 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
767 if (fd_peer_pidfd < 0)
768 goto out;
769
770 if (!get_pidfd_info(fd_peer_pidfd, &info))
771 goto out;
772
773 if (!(info.mask & PIDFD_INFO_COREDUMP))
774 goto out;
775
776 if (!(info.coredump_mask & PIDFD_COREDUMPED))
777 goto out;
778
779 fd_core_file = creat("/tmp/coredump.file", 0644);
780 if (fd_core_file < 0)
781 goto out;
782
783 if (!read_coredump_req(fd_coredump, &req))
784 goto out;
785
786 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
787 COREDUMP_KERNEL | COREDUMP_USERSPACE |
788 COREDUMP_REJECT | COREDUMP_WAIT))
789 goto out;
790
791 if (!send_coredump_ack(fd_coredump, &req,
792 COREDUMP_KERNEL | COREDUMP_WAIT, 0))
793 goto out;
794
795 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK))
796 goto out;
797
798 for (;;) {
799 char buffer[4096];
800 ssize_t bytes_read, bytes_write;
801
802 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
803 if (bytes_read < 0)
804 goto out;
805
806 if (bytes_read == 0)
807 break;
808
809 bytes_write = write(fd_core_file, buffer, bytes_read);
810 if (bytes_read != bytes_write)
811 goto out;
812 }
813
814 exit_code = EXIT_SUCCESS;
815out:
816 if (fd_core_file >= 0)
817 close(fd_core_file);
818 if (fd_peer_pidfd >= 0)
819 close(fd_peer_pidfd);
820 if (fd_coredump >= 0)
821 close(fd_coredump);
822 if (fd_server >= 0)
823 close(fd_server);
824 _exit(exit_code);
825 }
826 self->pid_coredump_server = pid_coredump_server;
827
828 EXPECT_EQ(close(ipc_sockets[1]), 0);
829 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
830 EXPECT_EQ(close(ipc_sockets[0]), 0);
831
832 pid = fork();
833 ASSERT_GE(pid, 0);
834 if (pid == 0)
835 crashing_child();
836
837 pidfd = sys_pidfd_open(pid, 0);
838 ASSERT_GE(pidfd, 0);
839
840 waitpid(pid, &status, 0);
841 ASSERT_TRUE(WIFSIGNALED(status));
842 ASSERT_TRUE(WCOREDUMP(status));
843
844 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
845 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
846 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
847
848 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
849
850 ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
851 ASSERT_GT(st.st_size, 0);
852 system("file /tmp/coredump.file");
853}
854
855TEST_F(coredump, socket_request_userspace)
856{
857 int pidfd, ret, status;
858 pid_t pid, pid_coredump_server;
859 struct pidfd_info info = {};
860 int ipc_sockets[2];
861 char c;
862
863 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
864
865 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
866 ASSERT_EQ(ret, 0);
867
868 pid_coredump_server = fork();
869 ASSERT_GE(pid_coredump_server, 0);
870 if (pid_coredump_server == 0) {
871 struct coredump_req req = {};
872 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
873 int exit_code = EXIT_FAILURE;
874
875 close(ipc_sockets[0]);
876
877 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
878 if (fd_server < 0)
879 goto out;
880
881 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
882 goto out;
883
884 close(ipc_sockets[1]);
885
886 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
887 if (fd_coredump < 0)
888 goto out;
889
890 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
891 if (fd_peer_pidfd < 0)
892 goto out;
893
894 if (!get_pidfd_info(fd_peer_pidfd, &info))
895 goto out;
896
897 if (!(info.mask & PIDFD_INFO_COREDUMP))
898 goto out;
899
900 if (!(info.coredump_mask & PIDFD_COREDUMPED))
901 goto out;
902
903 if (!read_coredump_req(fd_coredump, &req))
904 goto out;
905
906 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
907 COREDUMP_KERNEL | COREDUMP_USERSPACE |
908 COREDUMP_REJECT | COREDUMP_WAIT))
909 goto out;
910
911 if (!send_coredump_ack(fd_coredump, &req,
912 COREDUMP_USERSPACE | COREDUMP_WAIT, 0))
913 goto out;
914
915 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK))
916 goto out;
917
918 for (;;) {
919 char buffer[4096];
920 ssize_t bytes_read;
921
922 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
923 if (bytes_read > 0)
924 goto out;
925
926 if (bytes_read < 0)
927 goto out;
928
929 if (bytes_read == 0)
930 break;
931 }
932
933 exit_code = EXIT_SUCCESS;
934out:
935 if (fd_peer_pidfd >= 0)
936 close(fd_peer_pidfd);
937 if (fd_coredump >= 0)
938 close(fd_coredump);
939 if (fd_server >= 0)
940 close(fd_server);
941 _exit(exit_code);
942 }
943 self->pid_coredump_server = pid_coredump_server;
944
945 EXPECT_EQ(close(ipc_sockets[1]), 0);
946 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
947 EXPECT_EQ(close(ipc_sockets[0]), 0);
948
949 pid = fork();
950 ASSERT_GE(pid, 0);
951 if (pid == 0)
952 crashing_child();
953
954 pidfd = sys_pidfd_open(pid, 0);
955 ASSERT_GE(pidfd, 0);
956
957 waitpid(pid, &status, 0);
958 ASSERT_TRUE(WIFSIGNALED(status));
959 ASSERT_TRUE(WCOREDUMP(status));
960
961 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
962 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
963 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
964
965 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
966}
967
968TEST_F(coredump, socket_request_reject)
969{
970 int pidfd, ret, status;
971 pid_t pid, pid_coredump_server;
972 struct pidfd_info info = {};
973 int ipc_sockets[2];
974 char c;
975
976 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
977
978 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
979 ASSERT_EQ(ret, 0);
980
981 pid_coredump_server = fork();
982 ASSERT_GE(pid_coredump_server, 0);
983 if (pid_coredump_server == 0) {
984 struct coredump_req req = {};
985 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
986 int exit_code = EXIT_FAILURE;
987
988 close(ipc_sockets[0]);
989
990 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
991 if (fd_server < 0)
992 goto out;
993
994 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
995 goto out;
996
997 close(ipc_sockets[1]);
998
999 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1000 if (fd_coredump < 0)
1001 goto out;
1002
1003 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1004 if (fd_peer_pidfd < 0)
1005 goto out;
1006
1007 if (!get_pidfd_info(fd_peer_pidfd, &info))
1008 goto out;
1009
1010 if (!(info.mask & PIDFD_INFO_COREDUMP))
1011 goto out;
1012
1013 if (!(info.coredump_mask & PIDFD_COREDUMPED))
1014 goto out;
1015
1016 if (!read_coredump_req(fd_coredump, &req))
1017 goto out;
1018
1019 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1020 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1021 COREDUMP_REJECT | COREDUMP_WAIT))
1022 goto out;
1023
1024 if (!send_coredump_ack(fd_coredump, &req,
1025 COREDUMP_REJECT | COREDUMP_WAIT, 0))
1026 goto out;
1027
1028 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK))
1029 goto out;
1030
1031 for (;;) {
1032 char buffer[4096];
1033 ssize_t bytes_read;
1034
1035 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1036 if (bytes_read > 0)
1037 goto out;
1038
1039 if (bytes_read < 0)
1040 goto out;
1041
1042 if (bytes_read == 0)
1043 break;
1044 }
1045
1046 exit_code = EXIT_SUCCESS;
1047out:
1048 if (fd_peer_pidfd >= 0)
1049 close(fd_peer_pidfd);
1050 if (fd_coredump >= 0)
1051 close(fd_coredump);
1052 if (fd_server >= 0)
1053 close(fd_server);
1054 _exit(exit_code);
1055 }
1056 self->pid_coredump_server = pid_coredump_server;
1057
1058 EXPECT_EQ(close(ipc_sockets[1]), 0);
1059 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1060 EXPECT_EQ(close(ipc_sockets[0]), 0);
1061
1062 pid = fork();
1063 ASSERT_GE(pid, 0);
1064 if (pid == 0)
1065 crashing_child();
1066
1067 pidfd = sys_pidfd_open(pid, 0);
1068 ASSERT_GE(pidfd, 0);
1069
1070 waitpid(pid, &status, 0);
1071 ASSERT_TRUE(WIFSIGNALED(status));
1072 ASSERT_FALSE(WCOREDUMP(status));
1073
1074 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1075 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1076 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1077
1078 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1079}
1080
1081TEST_F(coredump, socket_request_invalid_flag_combination)
1082{
1083 int pidfd, ret, status;
1084 pid_t pid, pid_coredump_server;
1085 struct pidfd_info info = {};
1086 int ipc_sockets[2];
1087 char c;
1088
1089 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1090
1091 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1092 ASSERT_EQ(ret, 0);
1093
1094 pid_coredump_server = fork();
1095 ASSERT_GE(pid_coredump_server, 0);
1096 if (pid_coredump_server == 0) {
1097 struct coredump_req req = {};
1098 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1099 int exit_code = EXIT_FAILURE;
1100
1101 close(ipc_sockets[0]);
1102
1103 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1104 if (fd_server < 0)
1105 goto out;
1106
1107 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
1108 goto out;
1109
1110 close(ipc_sockets[1]);
1111
1112 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1113 if (fd_coredump < 0)
1114 goto out;
1115
1116 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1117 if (fd_peer_pidfd < 0)
1118 goto out;
1119
1120 if (!get_pidfd_info(fd_peer_pidfd, &info))
1121 goto out;
1122
1123 if (!(info.mask & PIDFD_INFO_COREDUMP))
1124 goto out;
1125
1126 if (!(info.coredump_mask & PIDFD_COREDUMPED))
1127 goto out;
1128
1129 if (!read_coredump_req(fd_coredump, &req))
1130 goto out;
1131
1132 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1133 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1134 COREDUMP_REJECT | COREDUMP_WAIT))
1135 goto out;
1136
1137 if (!send_coredump_ack(fd_coredump, &req,
1138 COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0))
1139 goto out;
1140
1141 if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING))
1142 goto out;
1143
1144 exit_code = EXIT_SUCCESS;
1145out:
1146 if (fd_peer_pidfd >= 0)
1147 close(fd_peer_pidfd);
1148 if (fd_coredump >= 0)
1149 close(fd_coredump);
1150 if (fd_server >= 0)
1151 close(fd_server);
1152 _exit(exit_code);
1153 }
1154 self->pid_coredump_server = pid_coredump_server;
1155
1156 EXPECT_EQ(close(ipc_sockets[1]), 0);
1157 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1158 EXPECT_EQ(close(ipc_sockets[0]), 0);
1159
1160 pid = fork();
1161 ASSERT_GE(pid, 0);
1162 if (pid == 0)
1163 crashing_child();
1164
1165 pidfd = sys_pidfd_open(pid, 0);
1166 ASSERT_GE(pidfd, 0);
1167
1168 waitpid(pid, &status, 0);
1169 ASSERT_TRUE(WIFSIGNALED(status));
1170 ASSERT_FALSE(WCOREDUMP(status));
1171
1172 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1173 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1174 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1175
1176 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1177}
1178
1179TEST_F(coredump, socket_request_unknown_flag)
1180{
1181 int pidfd, ret, status;
1182 pid_t pid, pid_coredump_server;
1183 struct pidfd_info info = {};
1184 int ipc_sockets[2];
1185 char c;
1186
1187 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1188
1189 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1190 ASSERT_EQ(ret, 0);
1191
1192 pid_coredump_server = fork();
1193 ASSERT_GE(pid_coredump_server, 0);
1194 if (pid_coredump_server == 0) {
1195 struct coredump_req req = {};
1196 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1197 int exit_code = EXIT_FAILURE;
1198
1199 close(ipc_sockets[0]);
1200
1201 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1202 if (fd_server < 0)
1203 goto out;
1204
1205 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
1206 goto out;
1207
1208 close(ipc_sockets[1]);
1209
1210 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1211 if (fd_coredump < 0)
1212 goto out;
1213
1214 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1215 if (fd_peer_pidfd < 0)
1216 goto out;
1217
1218 if (!get_pidfd_info(fd_peer_pidfd, &info))
1219 goto out;
1220
1221 if (!(info.mask & PIDFD_INFO_COREDUMP))
1222 goto out;
1223
1224 if (!(info.coredump_mask & PIDFD_COREDUMPED))
1225 goto out;
1226
1227 if (!read_coredump_req(fd_coredump, &req))
1228 goto out;
1229
1230 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1231 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1232 COREDUMP_REJECT | COREDUMP_WAIT))
1233 goto out;
1234
1235 if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0))
1236 goto out;
1237
1238 if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED))
1239 goto out;
1240
1241 exit_code = EXIT_SUCCESS;
1242out:
1243 if (fd_peer_pidfd >= 0)
1244 close(fd_peer_pidfd);
1245 if (fd_coredump >= 0)
1246 close(fd_coredump);
1247 if (fd_server >= 0)
1248 close(fd_server);
1249 _exit(exit_code);
1250 }
1251 self->pid_coredump_server = pid_coredump_server;
1252
1253 EXPECT_EQ(close(ipc_sockets[1]), 0);
1254 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1255 EXPECT_EQ(close(ipc_sockets[0]), 0);
1256
1257 pid = fork();
1258 ASSERT_GE(pid, 0);
1259 if (pid == 0)
1260 crashing_child();
1261
1262 pidfd = sys_pidfd_open(pid, 0);
1263 ASSERT_GE(pidfd, 0);
1264
1265 waitpid(pid, &status, 0);
1266 ASSERT_TRUE(WIFSIGNALED(status));
1267 ASSERT_FALSE(WCOREDUMP(status));
1268
1269 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1270 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1271 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1272
1273 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1274}
1275
1276TEST_F(coredump, socket_request_invalid_size_small)
1277{
1278 int pidfd, ret, status;
1279 pid_t pid, pid_coredump_server;
1280 struct pidfd_info info = {};
1281 int ipc_sockets[2];
1282 char c;
1283
1284 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1285
1286 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1287 ASSERT_EQ(ret, 0);
1288
1289 pid_coredump_server = fork();
1290 ASSERT_GE(pid_coredump_server, 0);
1291 if (pid_coredump_server == 0) {
1292 struct coredump_req req = {};
1293 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1294 int exit_code = EXIT_FAILURE;
1295
1296 close(ipc_sockets[0]);
1297
1298 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1299 if (fd_server < 0)
1300 goto out;
1301
1302 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
1303 goto out;
1304
1305 close(ipc_sockets[1]);
1306
1307 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1308 if (fd_coredump < 0)
1309 goto out;
1310
1311 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1312 if (fd_peer_pidfd < 0)
1313 goto out;
1314
1315 if (!get_pidfd_info(fd_peer_pidfd, &info))
1316 goto out;
1317
1318 if (!(info.mask & PIDFD_INFO_COREDUMP))
1319 goto out;
1320
1321 if (!(info.coredump_mask & PIDFD_COREDUMPED))
1322 goto out;
1323
1324 if (!read_coredump_req(fd_coredump, &req))
1325 goto out;
1326
1327 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1328 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1329 COREDUMP_REJECT | COREDUMP_WAIT))
1330 goto out;
1331
1332 if (!send_coredump_ack(fd_coredump, &req,
1333 COREDUMP_REJECT | COREDUMP_WAIT,
1334 COREDUMP_ACK_SIZE_VER0 / 2))
1335 goto out;
1336
1337 if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE))
1338 goto out;
1339
1340 exit_code = EXIT_SUCCESS;
1341out:
1342 if (fd_peer_pidfd >= 0)
1343 close(fd_peer_pidfd);
1344 if (fd_coredump >= 0)
1345 close(fd_coredump);
1346 if (fd_server >= 0)
1347 close(fd_server);
1348 _exit(exit_code);
1349 }
1350 self->pid_coredump_server = pid_coredump_server;
1351
1352 EXPECT_EQ(close(ipc_sockets[1]), 0);
1353 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1354 EXPECT_EQ(close(ipc_sockets[0]), 0);
1355
1356 pid = fork();
1357 ASSERT_GE(pid, 0);
1358 if (pid == 0)
1359 crashing_child();
1360
1361 pidfd = sys_pidfd_open(pid, 0);
1362 ASSERT_GE(pidfd, 0);
1363
1364 waitpid(pid, &status, 0);
1365 ASSERT_TRUE(WIFSIGNALED(status));
1366 ASSERT_FALSE(WCOREDUMP(status));
1367
1368 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1369 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1370 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1371
1372 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1373}
1374
1375TEST_F(coredump, socket_request_invalid_size_large)
1376{
1377 int pidfd, ret, status;
1378 pid_t pid, pid_coredump_server;
1379 struct pidfd_info info = {};
1380 int ipc_sockets[2];
1381 char c;
1382
1383 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1384
1385 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1386 ASSERT_EQ(ret, 0);
1387
1388 pid_coredump_server = fork();
1389 ASSERT_GE(pid_coredump_server, 0);
1390 if (pid_coredump_server == 0) {
1391 struct coredump_req req = {};
1392 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1393 int exit_code = EXIT_FAILURE;
1394
1395 close(ipc_sockets[0]);
1396
1397 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1398 if (fd_server < 0)
1399 goto out;
1400
1401 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
1402 goto out;
1403
1404 close(ipc_sockets[1]);
1405
1406 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1407 if (fd_coredump < 0)
1408 goto out;
1409
1410 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1411 if (fd_peer_pidfd < 0)
1412 goto out;
1413
1414 if (!get_pidfd_info(fd_peer_pidfd, &info))
1415 goto out;
1416
1417 if (!(info.mask & PIDFD_INFO_COREDUMP))
1418 goto out;
1419
1420 if (!(info.coredump_mask & PIDFD_COREDUMPED))
1421 goto out;
1422
1423 if (!read_coredump_req(fd_coredump, &req))
1424 goto out;
1425
1426 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1427 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1428 COREDUMP_REJECT | COREDUMP_WAIT))
1429 goto out;
1430
1431 if (!send_coredump_ack(fd_coredump, &req,
1432 COREDUMP_REJECT | COREDUMP_WAIT,
1433 COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE))
1434 goto out;
1435
1436 if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE))
1437 goto out;
1438
1439 exit_code = EXIT_SUCCESS;
1440out:
1441 if (fd_peer_pidfd >= 0)
1442 close(fd_peer_pidfd);
1443 if (fd_coredump >= 0)
1444 close(fd_coredump);
1445 if (fd_server >= 0)
1446 close(fd_server);
1447 _exit(exit_code);
1448 }
1449 self->pid_coredump_server = pid_coredump_server;
1450
1451 EXPECT_EQ(close(ipc_sockets[1]), 0);
1452 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1453 EXPECT_EQ(close(ipc_sockets[0]), 0);
1454
1455 pid = fork();
1456 ASSERT_GE(pid, 0);
1457 if (pid == 0)
1458 crashing_child();
1459
1460 pidfd = sys_pidfd_open(pid, 0);
1461 ASSERT_GE(pidfd, 0);
1462
1463 waitpid(pid, &status, 0);
1464 ASSERT_TRUE(WIFSIGNALED(status));
1465 ASSERT_FALSE(WCOREDUMP(status));
1466
1467 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1468 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1469 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1470
1471 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1472}
1473
1474static int open_coredump_tmpfile(int fd_tmpfs_detached)
1475{
1476 return openat(fd_tmpfs_detached, ".", O_TMPFILE | O_RDWR | O_EXCL, 0600);
1477}
1478
1479#define NUM_CRASHING_COREDUMPS 5
1480
1481TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500)
1482{
1483 int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1484 pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server;
1485 struct pidfd_info info = {};
1486 int ipc_sockets[2];
1487 char c;
1488
1489 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1490
1491 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1492
1493 pid_coredump_server = fork();
1494 ASSERT_GE(pid_coredump_server, 0);
1495 if (pid_coredump_server == 0) {
1496 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1497 int exit_code = EXIT_FAILURE;
1498 struct coredump_req req = {};
1499
1500 close(ipc_sockets[0]);
1501 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1502 if (fd_server < 0) {
1503 fprintf(stderr, "Failed to create and listen on unix socket\n");
1504 goto out;
1505 }
1506
1507 if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1508 fprintf(stderr, "Failed to notify parent via ipc socket\n");
1509 goto out;
1510 }
1511 close(ipc_sockets[1]);
1512
1513 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1514 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1515 if (fd_coredump < 0) {
1516 fprintf(stderr, "accept4 failed: %m\n");
1517 goto out;
1518 }
1519
1520 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1521 if (fd_peer_pidfd < 0) {
1522 fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump);
1523 goto out;
1524 }
1525
1526 if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1527 fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd);
1528 goto out;
1529 }
1530
1531 if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1532 fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd);
1533 goto out;
1534 }
1535 if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1536 fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd);
1537 goto out;
1538 }
1539
1540 if (!read_coredump_req(fd_coredump, &req)) {
1541 fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump);
1542 goto out;
1543 }
1544
1545 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1546 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1547 COREDUMP_REJECT | COREDUMP_WAIT)) {
1548 fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump);
1549 goto out;
1550 }
1551
1552 if (!send_coredump_ack(fd_coredump, &req,
1553 COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1554 fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump);
1555 goto out;
1556 }
1557
1558 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1559 fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump);
1560 goto out;
1561 }
1562
1563 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1564 if (fd_core_file < 0) {
1565 fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump);
1566 goto out;
1567 }
1568
1569 for (;;) {
1570 char buffer[4096];
1571 ssize_t bytes_read, bytes_write;
1572
1573 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1574 if (bytes_read < 0) {
1575 fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump);
1576 goto out;
1577 }
1578
1579 if (bytes_read == 0)
1580 break;
1581
1582 bytes_write = write(fd_core_file, buffer, bytes_read);
1583 if (bytes_read != bytes_write) {
1584 fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file);
1585 goto out;
1586 }
1587 }
1588
1589 close(fd_core_file);
1590 close(fd_peer_pidfd);
1591 close(fd_coredump);
1592 fd_peer_pidfd = -1;
1593 fd_coredump = -1;
1594 }
1595
1596 exit_code = EXIT_SUCCESS;
1597out:
1598 if (fd_core_file >= 0)
1599 close(fd_core_file);
1600 if (fd_peer_pidfd >= 0)
1601 close(fd_peer_pidfd);
1602 if (fd_coredump >= 0)
1603 close(fd_coredump);
1604 if (fd_server >= 0)
1605 close(fd_server);
1606 _exit(exit_code);
1607 }
1608 self->pid_coredump_server = pid_coredump_server;
1609
1610 EXPECT_EQ(close(ipc_sockets[1]), 0);
1611 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1612 EXPECT_EQ(close(ipc_sockets[0]), 0);
1613
1614 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1615 pid[i] = fork();
1616 ASSERT_GE(pid[i], 0);
1617 if (pid[i] == 0)
1618 crashing_child();
1619 pidfd[i] = sys_pidfd_open(pid[i], 0);
1620 ASSERT_GE(pidfd[i], 0);
1621 }
1622
1623 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1624 waitpid(pid[i], &status[i], 0);
1625 ASSERT_TRUE(WIFSIGNALED(status[i]));
1626 ASSERT_TRUE(WCOREDUMP(status[i]));
1627 }
1628
1629 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1630 info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1631 ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1632 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1633 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1634 }
1635
1636 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1637}
1638
1639#define MAX_EVENTS 128
1640
1641static void process_coredump_worker(int fd_coredump, int fd_peer_pidfd, int fd_core_file)
1642{
1643 int epfd = -1;
1644 int exit_code = EXIT_FAILURE;
1645
1646 epfd = epoll_create1(0);
1647 if (epfd < 0)
1648 goto out;
1649
1650 struct epoll_event ev;
1651 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
1652 ev.data.fd = fd_coredump;
1653 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd_coredump, &ev) < 0)
1654 goto out;
1655
1656 for (;;) {
1657 struct epoll_event events[1];
1658 int n = epoll_wait(epfd, events, 1, -1);
1659 if (n < 0)
1660 break;
1661
1662 if (events[0].events & (EPOLLIN | EPOLLRDHUP)) {
1663 for (;;) {
1664 char buffer[4096];
1665 ssize_t bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1666 if (bytes_read < 0) {
1667 if (errno == EAGAIN || errno == EWOULDBLOCK)
1668 break;
1669 goto out;
1670 }
1671 if (bytes_read == 0)
1672 goto done;
1673 ssize_t bytes_write = write(fd_core_file, buffer, bytes_read);
1674 if (bytes_write != bytes_read)
1675 goto out;
1676 }
1677 }
1678 }
1679
1680done:
1681 exit_code = EXIT_SUCCESS;
1682out:
1683 if (epfd >= 0)
1684 close(epfd);
1685 if (fd_core_file >= 0)
1686 close(fd_core_file);
1687 if (fd_peer_pidfd >= 0)
1688 close(fd_peer_pidfd);
1689 if (fd_coredump >= 0)
1690 close(fd_coredump);
1691 _exit(exit_code);
1692}
1693
1694TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500)
1695{
1696 int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1697 pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS];
1698 struct pidfd_info info = {};
1699 int ipc_sockets[2];
1700 char c;
1701
1702 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1703 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1704
1705 pid_coredump_server = fork();
1706 ASSERT_GE(pid_coredump_server, 0);
1707 if (pid_coredump_server == 0) {
1708 int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0;
1709 fd_server = -1;
1710 exit_code = EXIT_FAILURE;
1711 n_conns = 0;
1712 close(ipc_sockets[0]);
1713 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1714 if (fd_server < 0)
1715 goto out;
1716
1717 if (write_nointr(ipc_sockets[1], "1", 1) < 0)
1718 goto out;
1719 close(ipc_sockets[1]);
1720
1721 while (n_conns < NUM_CRASHING_COREDUMPS) {
1722 int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1723 struct coredump_req req = {};
1724 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1725 if (fd_coredump < 0) {
1726 if (errno == EAGAIN || errno == EWOULDBLOCK)
1727 continue;
1728 goto out;
1729 }
1730 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1731 if (fd_peer_pidfd < 0)
1732 goto out;
1733 if (!get_pidfd_info(fd_peer_pidfd, &info))
1734 goto out;
1735 if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED))
1736 goto out;
1737 if (!read_coredump_req(fd_coredump, &req))
1738 goto out;
1739 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1740 COREDUMP_KERNEL | COREDUMP_USERSPACE |
1741 COREDUMP_REJECT | COREDUMP_WAIT))
1742 goto out;
1743 if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0))
1744 goto out;
1745 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK))
1746 goto out;
1747 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1748 if (fd_core_file < 0)
1749 goto out;
1750 pid_t worker = fork();
1751 if (worker == 0) {
1752 close(fd_server);
1753 process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file);
1754 }
1755 worker_pids[n_conns] = worker;
1756 if (fd_coredump >= 0)
1757 close(fd_coredump);
1758 if (fd_peer_pidfd >= 0)
1759 close(fd_peer_pidfd);
1760 if (fd_core_file >= 0)
1761 close(fd_core_file);
1762 n_conns++;
1763 }
1764 exit_code = EXIT_SUCCESS;
1765out:
1766 if (fd_server >= 0)
1767 close(fd_server);
1768
1769 // Reap all worker processes
1770 for (int i = 0; i < n_conns; i++) {
1771 int wstatus;
1772 if (waitpid(worker_pids[i], &wstatus, 0) < 0) {
1773 fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]);
1774 } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) {
1775 fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus));
1776 exit_code = EXIT_FAILURE;
1777 }
1778 }
1779
1780 _exit(exit_code);
1781 }
1782 self->pid_coredump_server = pid_coredump_server;
1783
1784 EXPECT_EQ(close(ipc_sockets[1]), 0);
1785 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1786 EXPECT_EQ(close(ipc_sockets[0]), 0);
1787
1788 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1789 pid[i] = fork();
1790 ASSERT_GE(pid[i], 0);
1791 if (pid[i] == 0)
1792 crashing_child();
1793 pidfd[i] = sys_pidfd_open(pid[i], 0);
1794 ASSERT_GE(pidfd[i], 0);
1795 }
1796
1797 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1798 ASSERT_GE(waitpid(pid[i], &status[i], 0), 0);
1799 ASSERT_TRUE(WIFSIGNALED(status[i]));
1800 ASSERT_TRUE(WCOREDUMP(status[i]));
1801 }
1802
1803 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1804 info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1805 ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1806 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1807 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1808 }
1809
1810 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1811}
1812
1813TEST_F(coredump, socket_invalid_paths)
1814{
1815 ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket"));
1816 ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket"));
1817 ASSERT_FALSE(set_core_pattern("@../coredump.socket"));
1818 ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/.."));
1819 ASSERT_FALSE(set_core_pattern("@.."));
1820
1821 ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket"));
1822 ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket"));
1823 ASSERT_FALSE(set_core_pattern("@@../coredump.socket"));
1824 ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/.."));
1825 ASSERT_FALSE(set_core_pattern("@@.."));
1826
1827 ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket"));
1828}
1829
1830TEST_HARNESS_MAIN