File Index
Files and directories
Sign in
FILE

coredump_socket_protocol_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/coredump/coredump_socket_protocol_test.c C
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <sys/stat.h>
   4#include <sys/epoll.h>
   5#include <sys/socket.h>
   6#include <sys/un.h>
   7
   8#include "coredump_test.h"
   9
  10#define NUM_CRASHING_COREDUMPS 5
  11
  12FIXTURE_SETUP(coredump)
  13{
  14	FILE *file;
  15	int ret;
  16
  17	self->pid_coredump_server = -ESRCH;
  18	self->fd_tmpfs_detached = -1;
  19	file = fopen("/proc/sys/kernel/core_pattern", "r");
  20	ASSERT_NE(NULL, file);
  21
  22	ret = fread(self->original_core_pattern, 1, sizeof(self->original_core_pattern), file);
  23	ASSERT_TRUE(ret || feof(file));
  24	ASSERT_LT(ret, sizeof(self->original_core_pattern));
  25
  26	self->original_core_pattern[ret] = '\0';
  27	self->fd_tmpfs_detached = create_detached_tmpfs();
  28	ASSERT_GE(self->fd_tmpfs_detached, 0);
  29
  30	ret = fclose(file);
  31	ASSERT_EQ(0, ret);
  32}
  33
  34FIXTURE_TEARDOWN(coredump)
  35{
  36	const char *reason;
  37	FILE *file;
  38	int ret, status;
  39
  40	if (self->pid_coredump_server > 0) {
  41		kill(self->pid_coredump_server, SIGTERM);
  42		waitpid(self->pid_coredump_server, &status, 0);
  43	}
  44	unlink("/tmp/coredump.file");
  45	unlink("/tmp/coredump.socket");
  46
  47	file = fopen("/proc/sys/kernel/core_pattern", "w");
  48	if (!file) {
  49		reason = "Unable to open core_pattern";
  50		goto fail;
  51	}
  52
  53	ret = fprintf(file, "%s", self->original_core_pattern);
  54	if (ret < 0) {
  55		reason = "Unable to write to core_pattern";
  56		goto fail;
  57	}
  58
  59	ret = fclose(file);
  60	if (ret) {
  61		reason = "Unable to close core_pattern";
  62		goto fail;
  63	}
  64
  65	if (self->fd_tmpfs_detached >= 0) {
  66		ret = close(self->fd_tmpfs_detached);
  67		if (ret < 0) {
  68			reason = "Unable to close detached tmpfs";
  69			goto fail;
  70		}
  71		self->fd_tmpfs_detached = -1;
  72	}
  73
  74	return;
  75fail:
  76	/* This should never happen */
  77	fprintf(stderr, "Failed to cleanup coredump test: %s\n", reason);
  78}
  79
  80TEST_F(coredump, socket_request_kernel)
  81{
  82	int pidfd, ret, status;
  83	pid_t pid, pid_coredump_server;
  84	struct stat st;
  85	struct pidfd_info info = {};
  86	int ipc_sockets[2];
  87	char c;
  88
  89	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
  90
  91	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
  92	ASSERT_EQ(ret, 0);
  93
  94	pid_coredump_server = fork();
  95	ASSERT_GE(pid_coredump_server, 0);
  96	if (pid_coredump_server == 0) {
  97		struct coredump_req req = {};
  98		int fd_server = -1, fd_coredump = -1, fd_core_file = -1, fd_peer_pidfd = -1;
  99		int exit_code = EXIT_FAILURE;
 100
 101		close(ipc_sockets[0]);
 102
 103		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 104		if (fd_server < 0) {
 105			fprintf(stderr, "socket_request_kernel: create_and_listen_unix_socket failed: %m\n");
 106			goto out;
 107		}
 108
 109		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 110			fprintf(stderr, "socket_request_kernel: write_nointr to ipc socket failed: %m\n");
 111			goto out;
 112		}
 113
 114		close(ipc_sockets[1]);
 115
 116		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 117		if (fd_coredump < 0) {
 118			fprintf(stderr, "socket_request_kernel: accept4 failed: %m\n");
 119			goto out;
 120		}
 121
 122		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 123		if (fd_peer_pidfd < 0) {
 124			fprintf(stderr, "socket_request_kernel: get_peer_pidfd failed\n");
 125			goto out;
 126		}
 127
 128		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 129			fprintf(stderr, "socket_request_kernel: get_pidfd_info failed\n");
 130			goto out;
 131		}
 132
 133		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 134			fprintf(stderr, "socket_request_kernel: PIDFD_INFO_COREDUMP not set in mask\n");
 135			goto out;
 136		}
 137
 138		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 139			fprintf(stderr, "socket_request_kernel: PIDFD_COREDUMPED not set in coredump_mask\n");
 140			goto out;
 141		}
 142
 143		fd_core_file = creat("/tmp/coredump.file", 0644);
 144		if (fd_core_file < 0) {
 145			fprintf(stderr, "socket_request_kernel: creat coredump file failed: %m\n");
 146			goto out;
 147		}
 148
 149		if (!read_coredump_req(fd_coredump, &req)) {
 150			fprintf(stderr, "socket_request_kernel: read_coredump_req failed\n");
 151			goto out;
 152		}
 153
 154		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 155					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 156					COREDUMP_REJECT | COREDUMP_WAIT)) {
 157			fprintf(stderr, "socket_request_kernel: check_coredump_req failed\n");
 158			goto out;
 159		}
 160
 161		if (!send_coredump_ack(fd_coredump, &req,
 162				       COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
 163			fprintf(stderr, "socket_request_kernel: send_coredump_ack failed\n");
 164			goto out;
 165		}
 166
 167		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
 168			fprintf(stderr, "socket_request_kernel: read_marker COREDUMP_MARK_REQACK failed\n");
 169			goto out;
 170		}
 171
 172		for (;;) {
 173			char buffer[4096];
 174			ssize_t bytes_read, bytes_write;
 175
 176			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
 177			if (bytes_read < 0) {
 178				fprintf(stderr, "socket_request_kernel: read from coredump socket failed: %m\n");
 179				goto out;
 180			}
 181
 182			if (bytes_read == 0)
 183				break;
 184
 185			bytes_write = write(fd_core_file, buffer, bytes_read);
 186			if (bytes_read != bytes_write) {
 187				if (bytes_write < 0 && errno == ENOSPC)
 188					continue;
 189				fprintf(stderr, "socket_request_kernel: write to core file failed (read=%zd, write=%zd): %m\n",
 190					bytes_read, bytes_write);
 191				goto out;
 192			}
 193		}
 194
 195		exit_code = EXIT_SUCCESS;
 196		fprintf(stderr, "socket_request_kernel: completed successfully\n");
 197out:
 198		if (fd_core_file >= 0)
 199			close(fd_core_file);
 200		if (fd_peer_pidfd >= 0)
 201			close(fd_peer_pidfd);
 202		if (fd_coredump >= 0)
 203			close(fd_coredump);
 204		if (fd_server >= 0)
 205			close(fd_server);
 206		_exit(exit_code);
 207	}
 208	self->pid_coredump_server = pid_coredump_server;
 209
 210	EXPECT_EQ(close(ipc_sockets[1]), 0);
 211	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 212	EXPECT_EQ(close(ipc_sockets[0]), 0);
 213
 214	pid = fork();
 215	ASSERT_GE(pid, 0);
 216	if (pid == 0)
 217		crashing_child();
 218
 219	pidfd = sys_pidfd_open(pid, 0);
 220	ASSERT_GE(pidfd, 0);
 221
 222	waitpid(pid, &status, 0);
 223	ASSERT_TRUE(WIFSIGNALED(status));
 224	ASSERT_TRUE(WCOREDUMP(status));
 225
 226	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 227	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 228	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 229
 230	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
 231
 232	ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
 233	ASSERT_GT(st.st_size, 0);
 234	system("file /tmp/coredump.file");
 235}
 236
 237TEST_F(coredump, socket_request_userspace)
 238{
 239	int pidfd, ret, status;
 240	pid_t pid, pid_coredump_server;
 241	struct pidfd_info info = {};
 242	int ipc_sockets[2];
 243	char c;
 244
 245	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
 246
 247	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 248	ASSERT_EQ(ret, 0);
 249
 250	pid_coredump_server = fork();
 251	ASSERT_GE(pid_coredump_server, 0);
 252	if (pid_coredump_server == 0) {
 253		struct coredump_req req = {};
 254		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
 255		int exit_code = EXIT_FAILURE;
 256
 257		close(ipc_sockets[0]);
 258
 259		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 260		if (fd_server < 0) {
 261			fprintf(stderr, "socket_request_userspace: create_and_listen_unix_socket failed: %m\n");
 262			goto out;
 263		}
 264
 265		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 266			fprintf(stderr, "socket_request_userspace: write_nointr to ipc socket failed: %m\n");
 267			goto out;
 268		}
 269
 270		close(ipc_sockets[1]);
 271
 272		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 273		if (fd_coredump < 0) {
 274			fprintf(stderr, "socket_request_userspace: accept4 failed: %m\n");
 275			goto out;
 276		}
 277
 278		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 279		if (fd_peer_pidfd < 0) {
 280			fprintf(stderr, "socket_request_userspace: get_peer_pidfd failed\n");
 281			goto out;
 282		}
 283
 284		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 285			fprintf(stderr, "socket_request_userspace: get_pidfd_info failed\n");
 286			goto out;
 287		}
 288
 289		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 290			fprintf(stderr, "socket_request_userspace: PIDFD_INFO_COREDUMP not set in mask\n");
 291			goto out;
 292		}
 293
 294		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 295			fprintf(stderr, "socket_request_userspace: PIDFD_COREDUMPED not set in coredump_mask\n");
 296			goto out;
 297		}
 298
 299		if (!read_coredump_req(fd_coredump, &req)) {
 300			fprintf(stderr, "socket_request_userspace: read_coredump_req failed\n");
 301			goto out;
 302		}
 303
 304		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 305					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 306					COREDUMP_REJECT | COREDUMP_WAIT)) {
 307			fprintf(stderr, "socket_request_userspace: check_coredump_req failed\n");
 308			goto out;
 309		}
 310
 311		if (!send_coredump_ack(fd_coredump, &req,
 312				       COREDUMP_USERSPACE | COREDUMP_WAIT, 0)) {
 313			fprintf(stderr, "socket_request_userspace: send_coredump_ack failed\n");
 314			goto out;
 315		}
 316
 317		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
 318			fprintf(stderr, "socket_request_userspace: read_marker COREDUMP_MARK_REQACK failed\n");
 319			goto out;
 320		}
 321
 322		for (;;) {
 323			char buffer[4096];
 324			ssize_t bytes_read;
 325
 326			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
 327			if (bytes_read > 0) {
 328				fprintf(stderr, "socket_request_userspace: unexpected data received (expected no coredump data)\n");
 329				goto out;
 330			}
 331
 332			if (bytes_read < 0) {
 333				fprintf(stderr, "socket_request_userspace: read from coredump socket failed: %m\n");
 334				goto out;
 335			}
 336
 337			if (bytes_read == 0)
 338				break;
 339		}
 340
 341		exit_code = EXIT_SUCCESS;
 342		fprintf(stderr, "socket_request_userspace: completed successfully\n");
 343out:
 344		if (fd_peer_pidfd >= 0)
 345			close(fd_peer_pidfd);
 346		if (fd_coredump >= 0)
 347			close(fd_coredump);
 348		if (fd_server >= 0)
 349			close(fd_server);
 350		_exit(exit_code);
 351	}
 352	self->pid_coredump_server = pid_coredump_server;
 353
 354	EXPECT_EQ(close(ipc_sockets[1]), 0);
 355	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 356	EXPECT_EQ(close(ipc_sockets[0]), 0);
 357
 358	pid = fork();
 359	ASSERT_GE(pid, 0);
 360	if (pid == 0)
 361		crashing_child();
 362
 363	pidfd = sys_pidfd_open(pid, 0);
 364	ASSERT_GE(pidfd, 0);
 365
 366	waitpid(pid, &status, 0);
 367	ASSERT_TRUE(WIFSIGNALED(status));
 368	ASSERT_TRUE(WCOREDUMP(status));
 369
 370	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 371	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 372	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 373
 374	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
 375}
 376
 377TEST_F(coredump, socket_request_reject)
 378{
 379	int pidfd, ret, status;
 380	pid_t pid, pid_coredump_server;
 381	struct pidfd_info info = {};
 382	int ipc_sockets[2];
 383	char c;
 384
 385	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
 386
 387	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 388	ASSERT_EQ(ret, 0);
 389
 390	pid_coredump_server = fork();
 391	ASSERT_GE(pid_coredump_server, 0);
 392	if (pid_coredump_server == 0) {
 393		struct coredump_req req = {};
 394		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
 395		int exit_code = EXIT_FAILURE;
 396
 397		close(ipc_sockets[0]);
 398
 399		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 400		if (fd_server < 0) {
 401			fprintf(stderr, "socket_request_reject: create_and_listen_unix_socket failed: %m\n");
 402			goto out;
 403		}
 404
 405		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 406			fprintf(stderr, "socket_request_reject: write_nointr to ipc socket failed: %m\n");
 407			goto out;
 408		}
 409
 410		close(ipc_sockets[1]);
 411
 412		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 413		if (fd_coredump < 0) {
 414			fprintf(stderr, "socket_request_reject: accept4 failed: %m\n");
 415			goto out;
 416		}
 417
 418		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 419		if (fd_peer_pidfd < 0) {
 420			fprintf(stderr, "socket_request_reject: get_peer_pidfd failed\n");
 421			goto out;
 422		}
 423
 424		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 425			fprintf(stderr, "socket_request_reject: get_pidfd_info failed\n");
 426			goto out;
 427		}
 428
 429		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 430			fprintf(stderr, "socket_request_reject: PIDFD_INFO_COREDUMP not set in mask\n");
 431			goto out;
 432		}
 433
 434		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 435			fprintf(stderr, "socket_request_reject: PIDFD_COREDUMPED not set in coredump_mask\n");
 436			goto out;
 437		}
 438
 439		if (!read_coredump_req(fd_coredump, &req)) {
 440			fprintf(stderr, "socket_request_reject: read_coredump_req failed\n");
 441			goto out;
 442		}
 443
 444		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 445					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 446					COREDUMP_REJECT | COREDUMP_WAIT)) {
 447			fprintf(stderr, "socket_request_reject: check_coredump_req failed\n");
 448			goto out;
 449		}
 450
 451		if (!send_coredump_ack(fd_coredump, &req,
 452				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
 453			fprintf(stderr, "socket_request_reject: send_coredump_ack failed\n");
 454			goto out;
 455		}
 456
 457		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
 458			fprintf(stderr, "socket_request_reject: read_marker COREDUMP_MARK_REQACK failed\n");
 459			goto out;
 460		}
 461
 462		for (;;) {
 463			char buffer[4096];
 464			ssize_t bytes_read;
 465
 466			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
 467			if (bytes_read > 0) {
 468				fprintf(stderr, "socket_request_reject: unexpected data received (expected no coredump data for REJECT)\n");
 469				goto out;
 470			}
 471
 472			if (bytes_read < 0) {
 473				fprintf(stderr, "socket_request_reject: read from coredump socket failed: %m\n");
 474				goto out;
 475			}
 476
 477			if (bytes_read == 0)
 478				break;
 479		}
 480
 481		exit_code = EXIT_SUCCESS;
 482		fprintf(stderr, "socket_request_reject: completed successfully\n");
 483out:
 484		if (fd_peer_pidfd >= 0)
 485			close(fd_peer_pidfd);
 486		if (fd_coredump >= 0)
 487			close(fd_coredump);
 488		if (fd_server >= 0)
 489			close(fd_server);
 490		_exit(exit_code);
 491	}
 492	self->pid_coredump_server = pid_coredump_server;
 493
 494	EXPECT_EQ(close(ipc_sockets[1]), 0);
 495	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 496	EXPECT_EQ(close(ipc_sockets[0]), 0);
 497
 498	pid = fork();
 499	ASSERT_GE(pid, 0);
 500	if (pid == 0)
 501		crashing_child();
 502
 503	pidfd = sys_pidfd_open(pid, 0);
 504	ASSERT_GE(pidfd, 0);
 505
 506	waitpid(pid, &status, 0);
 507	ASSERT_TRUE(WIFSIGNALED(status));
 508	ASSERT_FALSE(WCOREDUMP(status));
 509
 510	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 511	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 512	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 513
 514	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
 515}
 516
 517TEST_F(coredump, socket_request_invalid_flag_combination)
 518{
 519	int pidfd, ret, status;
 520	pid_t pid, pid_coredump_server;
 521	struct pidfd_info info = {};
 522	int ipc_sockets[2];
 523	char c;
 524
 525	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
 526
 527	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 528	ASSERT_EQ(ret, 0);
 529
 530	pid_coredump_server = fork();
 531	ASSERT_GE(pid_coredump_server, 0);
 532	if (pid_coredump_server == 0) {
 533		struct coredump_req req = {};
 534		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
 535		int exit_code = EXIT_FAILURE;
 536
 537		close(ipc_sockets[0]);
 538
 539		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 540		if (fd_server < 0) {
 541			fprintf(stderr, "socket_request_invalid_flag_combination: create_and_listen_unix_socket failed: %m\n");
 542			goto out;
 543		}
 544
 545		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 546			fprintf(stderr, "socket_request_invalid_flag_combination: write_nointr to ipc socket failed: %m\n");
 547			goto out;
 548		}
 549
 550		close(ipc_sockets[1]);
 551
 552		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 553		if (fd_coredump < 0) {
 554			fprintf(stderr, "socket_request_invalid_flag_combination: accept4 failed: %m\n");
 555			goto out;
 556		}
 557
 558		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 559		if (fd_peer_pidfd < 0) {
 560			fprintf(stderr, "socket_request_invalid_flag_combination: get_peer_pidfd failed\n");
 561			goto out;
 562		}
 563
 564		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 565			fprintf(stderr, "socket_request_invalid_flag_combination: get_pidfd_info failed\n");
 566			goto out;
 567		}
 568
 569		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 570			fprintf(stderr, "socket_request_invalid_flag_combination: PIDFD_INFO_COREDUMP not set in mask\n");
 571			goto out;
 572		}
 573
 574		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 575			fprintf(stderr, "socket_request_invalid_flag_combination: PIDFD_COREDUMPED not set in coredump_mask\n");
 576			goto out;
 577		}
 578
 579		if (!read_coredump_req(fd_coredump, &req)) {
 580			fprintf(stderr, "socket_request_invalid_flag_combination: read_coredump_req failed\n");
 581			goto out;
 582		}
 583
 584		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 585					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 586					COREDUMP_REJECT | COREDUMP_WAIT)) {
 587			fprintf(stderr, "socket_request_invalid_flag_combination: check_coredump_req failed\n");
 588			goto out;
 589		}
 590
 591		if (!send_coredump_ack(fd_coredump, &req,
 592				       COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
 593			fprintf(stderr, "socket_request_invalid_flag_combination: send_coredump_ack failed\n");
 594			goto out;
 595		}
 596
 597		if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) {
 598			fprintf(stderr, "socket_request_invalid_flag_combination: read_marker COREDUMP_MARK_CONFLICTING failed\n");
 599			goto out;
 600		}
 601
 602		exit_code = EXIT_SUCCESS;
 603		fprintf(stderr, "socket_request_invalid_flag_combination: completed successfully\n");
 604out:
 605		if (fd_peer_pidfd >= 0)
 606			close(fd_peer_pidfd);
 607		if (fd_coredump >= 0)
 608			close(fd_coredump);
 609		if (fd_server >= 0)
 610			close(fd_server);
 611		_exit(exit_code);
 612	}
 613	self->pid_coredump_server = pid_coredump_server;
 614
 615	EXPECT_EQ(close(ipc_sockets[1]), 0);
 616	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 617	EXPECT_EQ(close(ipc_sockets[0]), 0);
 618
 619	pid = fork();
 620	ASSERT_GE(pid, 0);
 621	if (pid == 0)
 622		crashing_child();
 623
 624	pidfd = sys_pidfd_open(pid, 0);
 625	ASSERT_GE(pidfd, 0);
 626
 627	waitpid(pid, &status, 0);
 628	ASSERT_TRUE(WIFSIGNALED(status));
 629	ASSERT_FALSE(WCOREDUMP(status));
 630
 631	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 632	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 633	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 634
 635	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
 636}
 637
 638TEST_F(coredump, socket_request_unknown_flag)
 639{
 640	int pidfd, ret, status;
 641	pid_t pid, pid_coredump_server;
 642	struct pidfd_info info = {};
 643	int ipc_sockets[2];
 644	char c;
 645
 646	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
 647
 648	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 649	ASSERT_EQ(ret, 0);
 650
 651	pid_coredump_server = fork();
 652	ASSERT_GE(pid_coredump_server, 0);
 653	if (pid_coredump_server == 0) {
 654		struct coredump_req req = {};
 655		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
 656		int exit_code = EXIT_FAILURE;
 657
 658		close(ipc_sockets[0]);
 659
 660		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 661		if (fd_server < 0) {
 662			fprintf(stderr, "socket_request_unknown_flag: create_and_listen_unix_socket failed: %m\n");
 663			goto out;
 664		}
 665
 666		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 667			fprintf(stderr, "socket_request_unknown_flag: write_nointr to ipc socket failed: %m\n");
 668			goto out;
 669		}
 670
 671		close(ipc_sockets[1]);
 672
 673		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 674		if (fd_coredump < 0) {
 675			fprintf(stderr, "socket_request_unknown_flag: accept4 failed: %m\n");
 676			goto out;
 677		}
 678
 679		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 680		if (fd_peer_pidfd < 0) {
 681			fprintf(stderr, "socket_request_unknown_flag: get_peer_pidfd failed\n");
 682			goto out;
 683		}
 684
 685		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 686			fprintf(stderr, "socket_request_unknown_flag: get_pidfd_info failed\n");
 687			goto out;
 688		}
 689
 690		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 691			fprintf(stderr, "socket_request_unknown_flag: PIDFD_INFO_COREDUMP not set in mask\n");
 692			goto out;
 693		}
 694
 695		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 696			fprintf(stderr, "socket_request_unknown_flag: PIDFD_COREDUMPED not set in coredump_mask\n");
 697			goto out;
 698		}
 699
 700		if (!read_coredump_req(fd_coredump, &req)) {
 701			fprintf(stderr, "socket_request_unknown_flag: read_coredump_req failed\n");
 702			goto out;
 703		}
 704
 705		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 706					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 707					COREDUMP_REJECT | COREDUMP_WAIT)) {
 708			fprintf(stderr, "socket_request_unknown_flag: check_coredump_req failed\n");
 709			goto out;
 710		}
 711
 712		if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0)) {
 713			fprintf(stderr, "socket_request_unknown_flag: send_coredump_ack failed\n");
 714			goto out;
 715		}
 716
 717		if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED)) {
 718			fprintf(stderr, "socket_request_unknown_flag: read_marker COREDUMP_MARK_UNSUPPORTED failed\n");
 719			goto out;
 720		}
 721
 722		exit_code = EXIT_SUCCESS;
 723		fprintf(stderr, "socket_request_unknown_flag: completed successfully\n");
 724out:
 725		if (fd_peer_pidfd >= 0)
 726			close(fd_peer_pidfd);
 727		if (fd_coredump >= 0)
 728			close(fd_coredump);
 729		if (fd_server >= 0)
 730			close(fd_server);
 731		_exit(exit_code);
 732	}
 733	self->pid_coredump_server = pid_coredump_server;
 734
 735	EXPECT_EQ(close(ipc_sockets[1]), 0);
 736	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 737	EXPECT_EQ(close(ipc_sockets[0]), 0);
 738
 739	pid = fork();
 740	ASSERT_GE(pid, 0);
 741	if (pid == 0)
 742		crashing_child();
 743
 744	pidfd = sys_pidfd_open(pid, 0);
 745	ASSERT_GE(pidfd, 0);
 746
 747	waitpid(pid, &status, 0);
 748	ASSERT_TRUE(WIFSIGNALED(status));
 749	ASSERT_FALSE(WCOREDUMP(status));
 750
 751	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 752	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 753	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 754
 755	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
 756}
 757
 758TEST_F(coredump, socket_request_invalid_size_small)
 759{
 760	int pidfd, ret, status;
 761	pid_t pid, pid_coredump_server;
 762	struct pidfd_info info = {};
 763	int ipc_sockets[2];
 764	char c;
 765
 766	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
 767
 768	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 769	ASSERT_EQ(ret, 0);
 770
 771	pid_coredump_server = fork();
 772	ASSERT_GE(pid_coredump_server, 0);
 773	if (pid_coredump_server == 0) {
 774		struct coredump_req req = {};
 775		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
 776		int exit_code = EXIT_FAILURE;
 777
 778		close(ipc_sockets[0]);
 779
 780		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 781		if (fd_server < 0) {
 782			fprintf(stderr, "socket_request_invalid_size_small: create_and_listen_unix_socket failed: %m\n");
 783			goto out;
 784		}
 785
 786		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 787			fprintf(stderr, "socket_request_invalid_size_small: write_nointr to ipc socket failed: %m\n");
 788			goto out;
 789		}
 790
 791		close(ipc_sockets[1]);
 792
 793		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 794		if (fd_coredump < 0) {
 795			fprintf(stderr, "socket_request_invalid_size_small: accept4 failed: %m\n");
 796			goto out;
 797		}
 798
 799		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 800		if (fd_peer_pidfd < 0) {
 801			fprintf(stderr, "socket_request_invalid_size_small: get_peer_pidfd failed\n");
 802			goto out;
 803		}
 804
 805		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 806			fprintf(stderr, "socket_request_invalid_size_small: get_pidfd_info failed\n");
 807			goto out;
 808		}
 809
 810		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 811			fprintf(stderr, "socket_request_invalid_size_small: PIDFD_INFO_COREDUMP not set in mask\n");
 812			goto out;
 813		}
 814
 815		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 816			fprintf(stderr, "socket_request_invalid_size_small: PIDFD_COREDUMPED not set in coredump_mask\n");
 817			goto out;
 818		}
 819
 820		if (!read_coredump_req(fd_coredump, &req)) {
 821			fprintf(stderr, "socket_request_invalid_size_small: read_coredump_req failed\n");
 822			goto out;
 823		}
 824
 825		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 826					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 827					COREDUMP_REJECT | COREDUMP_WAIT)) {
 828			fprintf(stderr, "socket_request_invalid_size_small: check_coredump_req failed\n");
 829			goto out;
 830		}
 831
 832		if (!send_coredump_ack(fd_coredump, &req,
 833				       COREDUMP_REJECT | COREDUMP_WAIT,
 834				       COREDUMP_ACK_SIZE_VER0 / 2)) {
 835			fprintf(stderr, "socket_request_invalid_size_small: send_coredump_ack failed\n");
 836			goto out;
 837		}
 838
 839		if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE)) {
 840			fprintf(stderr, "socket_request_invalid_size_small: read_marker COREDUMP_MARK_MINSIZE failed\n");
 841			goto out;
 842		}
 843
 844		exit_code = EXIT_SUCCESS;
 845		fprintf(stderr, "socket_request_invalid_size_small: completed successfully\n");
 846out:
 847		if (fd_peer_pidfd >= 0)
 848			close(fd_peer_pidfd);
 849		if (fd_coredump >= 0)
 850			close(fd_coredump);
 851		if (fd_server >= 0)
 852			close(fd_server);
 853		_exit(exit_code);
 854	}
 855	self->pid_coredump_server = pid_coredump_server;
 856
 857	EXPECT_EQ(close(ipc_sockets[1]), 0);
 858	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 859	EXPECT_EQ(close(ipc_sockets[0]), 0);
 860
 861	pid = fork();
 862	ASSERT_GE(pid, 0);
 863	if (pid == 0)
 864		crashing_child();
 865
 866	pidfd = sys_pidfd_open(pid, 0);
 867	ASSERT_GE(pidfd, 0);
 868
 869	waitpid(pid, &status, 0);
 870	ASSERT_TRUE(WIFSIGNALED(status));
 871	ASSERT_FALSE(WCOREDUMP(status));
 872
 873	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 874	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 875	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 876
 877	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
 878}
 879
 880TEST_F(coredump, socket_request_invalid_size_large)
 881{
 882	int pidfd, ret, status;
 883	pid_t pid, pid_coredump_server;
 884	struct pidfd_info info = {};
 885	int ipc_sockets[2];
 886	char c;
 887
 888	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
 889
 890	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 891	ASSERT_EQ(ret, 0);
 892
 893	pid_coredump_server = fork();
 894	ASSERT_GE(pid_coredump_server, 0);
 895	if (pid_coredump_server == 0) {
 896		struct coredump_req req = {};
 897		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
 898		int exit_code = EXIT_FAILURE;
 899
 900		close(ipc_sockets[0]);
 901
 902		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
 903		if (fd_server < 0) {
 904			fprintf(stderr, "socket_request_invalid_size_large: create_and_listen_unix_socket failed: %m\n");
 905			goto out;
 906		}
 907
 908		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
 909			fprintf(stderr, "socket_request_invalid_size_large: write_nointr to ipc socket failed: %m\n");
 910			goto out;
 911		}
 912
 913		close(ipc_sockets[1]);
 914
 915		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
 916		if (fd_coredump < 0) {
 917			fprintf(stderr, "socket_request_invalid_size_large: accept4 failed: %m\n");
 918			goto out;
 919		}
 920
 921		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
 922		if (fd_peer_pidfd < 0) {
 923			fprintf(stderr, "socket_request_invalid_size_large: get_peer_pidfd failed\n");
 924			goto out;
 925		}
 926
 927		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
 928			fprintf(stderr, "socket_request_invalid_size_large: get_pidfd_info failed\n");
 929			goto out;
 930		}
 931
 932		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
 933			fprintf(stderr, "socket_request_invalid_size_large: PIDFD_INFO_COREDUMP not set in mask\n");
 934			goto out;
 935		}
 936
 937		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
 938			fprintf(stderr, "socket_request_invalid_size_large: PIDFD_COREDUMPED not set in coredump_mask\n");
 939			goto out;
 940		}
 941
 942		if (!read_coredump_req(fd_coredump, &req)) {
 943			fprintf(stderr, "socket_request_invalid_size_large: read_coredump_req failed\n");
 944			goto out;
 945		}
 946
 947		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
 948					COREDUMP_KERNEL | COREDUMP_USERSPACE |
 949					COREDUMP_REJECT | COREDUMP_WAIT)) {
 950			fprintf(stderr, "socket_request_invalid_size_large: check_coredump_req failed\n");
 951			goto out;
 952		}
 953
 954		if (!send_coredump_ack(fd_coredump, &req,
 955				       COREDUMP_REJECT | COREDUMP_WAIT,
 956				       COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE)) {
 957			fprintf(stderr, "socket_request_invalid_size_large: send_coredump_ack failed\n");
 958			goto out;
 959		}
 960
 961		if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE)) {
 962			fprintf(stderr, "socket_request_invalid_size_large: read_marker COREDUMP_MARK_MAXSIZE failed\n");
 963			goto out;
 964		}
 965
 966		exit_code = EXIT_SUCCESS;
 967		fprintf(stderr, "socket_request_invalid_size_large: completed successfully\n");
 968out:
 969		if (fd_peer_pidfd >= 0)
 970			close(fd_peer_pidfd);
 971		if (fd_coredump >= 0)
 972			close(fd_coredump);
 973		if (fd_server >= 0)
 974			close(fd_server);
 975		_exit(exit_code);
 976	}
 977	self->pid_coredump_server = pid_coredump_server;
 978
 979	EXPECT_EQ(close(ipc_sockets[1]), 0);
 980	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
 981	EXPECT_EQ(close(ipc_sockets[0]), 0);
 982
 983	pid = fork();
 984	ASSERT_GE(pid, 0);
 985	if (pid == 0)
 986		crashing_child();
 987
 988	pidfd = sys_pidfd_open(pid, 0);
 989	ASSERT_GE(pidfd, 0);
 990
 991	waitpid(pid, &status, 0);
 992	ASSERT_TRUE(WIFSIGNALED(status));
 993	ASSERT_FALSE(WCOREDUMP(status));
 994
 995	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
 996	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
 997	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
 998
 999	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1000}
1001
1002/*
1003 * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGSEGV
1004 *
1005 * Verify that when using socket-based coredump protocol,
1006 * the coredump_signal field is correctly exposed as SIGSEGV.
1007 */
1008TEST_F(coredump, socket_coredump_signal_sigsegv)
1009{
1010	int pidfd, ret, status;
1011	pid_t pid, pid_coredump_server;
1012	struct pidfd_info info = {};
1013	int ipc_sockets[2];
1014	char c;
1015
1016	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1017
1018	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1019	ASSERT_EQ(ret, 0);
1020
1021	pid_coredump_server = fork();
1022	ASSERT_GE(pid_coredump_server, 0);
1023	if (pid_coredump_server == 0) {
1024		struct coredump_req req = {};
1025		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1026		int exit_code = EXIT_FAILURE;
1027
1028		close(ipc_sockets[0]);
1029
1030		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1031		if (fd_server < 0) {
1032			fprintf(stderr, "socket_coredump_signal_sigsegv: create_and_listen_unix_socket failed: %m\n");
1033			goto out;
1034		}
1035
1036		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1037			fprintf(stderr, "socket_coredump_signal_sigsegv: write_nointr to ipc socket failed: %m\n");
1038			goto out;
1039		}
1040
1041		close(ipc_sockets[1]);
1042
1043		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1044		if (fd_coredump < 0) {
1045			fprintf(stderr, "socket_coredump_signal_sigsegv: accept4 failed: %m\n");
1046			goto out;
1047		}
1048
1049		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1050		if (fd_peer_pidfd < 0) {
1051			fprintf(stderr, "socket_coredump_signal_sigsegv: get_peer_pidfd failed\n");
1052			goto out;
1053		}
1054
1055		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1056			fprintf(stderr, "socket_coredump_signal_sigsegv: get_pidfd_info failed\n");
1057			goto out;
1058		}
1059
1060		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1061			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP not set in mask\n");
1062			goto out;
1063		}
1064
1065		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1066			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_COREDUMPED not set in coredump_mask\n");
1067			goto out;
1068		}
1069
1070		/* Verify coredump_signal is available and correct */
1071		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
1072			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
1073			goto out;
1074		}
1075
1076		if (info.coredump_signal != SIGSEGV) {
1077			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_signal=%d, expected SIGSEGV=%d\n",
1078				info.coredump_signal, SIGSEGV);
1079			goto out;
1080		}
1081
1082		if (!read_coredump_req(fd_coredump, &req)) {
1083			fprintf(stderr, "socket_coredump_signal_sigsegv: read_coredump_req failed\n");
1084			goto out;
1085		}
1086
1087		if (!send_coredump_ack(fd_coredump, &req,
1088				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
1089			fprintf(stderr, "socket_coredump_signal_sigsegv: send_coredump_ack failed\n");
1090			goto out;
1091		}
1092
1093		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1094			fprintf(stderr, "socket_coredump_signal_sigsegv: read_marker COREDUMP_MARK_REQACK failed\n");
1095			goto out;
1096		}
1097
1098		exit_code = EXIT_SUCCESS;
1099		fprintf(stderr, "socket_coredump_signal_sigsegv: completed successfully\n");
1100out:
1101		if (fd_peer_pidfd >= 0)
1102			close(fd_peer_pidfd);
1103		if (fd_coredump >= 0)
1104			close(fd_coredump);
1105		if (fd_server >= 0)
1106			close(fd_server);
1107		_exit(exit_code);
1108	}
1109	self->pid_coredump_server = pid_coredump_server;
1110
1111	EXPECT_EQ(close(ipc_sockets[1]), 0);
1112	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1113	EXPECT_EQ(close(ipc_sockets[0]), 0);
1114
1115	pid = fork();
1116	ASSERT_GE(pid, 0);
1117	if (pid == 0)
1118		crashing_child();
1119
1120	pidfd = sys_pidfd_open(pid, 0);
1121	ASSERT_GE(pidfd, 0);
1122
1123	waitpid(pid, &status, 0);
1124	ASSERT_TRUE(WIFSIGNALED(status));
1125	ASSERT_EQ(WTERMSIG(status), SIGSEGV);
1126
1127	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1128	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
1129	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
1130	ASSERT_EQ(info.coredump_signal, SIGSEGV);
1131
1132	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1133}
1134
1135/*
1136 * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGABRT
1137 *
1138 * Verify that when using socket-based coredump protocol,
1139 * the coredump_signal field is correctly exposed as SIGABRT.
1140 */
1141TEST_F(coredump, socket_coredump_signal_sigabrt)
1142{
1143	int pidfd, ret, status;
1144	pid_t pid, pid_coredump_server;
1145	struct pidfd_info info = {};
1146	int ipc_sockets[2];
1147	char c;
1148
1149	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1150
1151	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1152	ASSERT_EQ(ret, 0);
1153
1154	pid_coredump_server = fork();
1155	ASSERT_GE(pid_coredump_server, 0);
1156	if (pid_coredump_server == 0) {
1157		struct coredump_req req = {};
1158		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1159		int exit_code = EXIT_FAILURE;
1160
1161		close(ipc_sockets[0]);
1162
1163		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1164		if (fd_server < 0) {
1165			fprintf(stderr, "socket_coredump_signal_sigabrt: create_and_listen_unix_socket failed: %m\n");
1166			goto out;
1167		}
1168
1169		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1170			fprintf(stderr, "socket_coredump_signal_sigabrt: write_nointr to ipc socket failed: %m\n");
1171			goto out;
1172		}
1173
1174		close(ipc_sockets[1]);
1175
1176		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1177		if (fd_coredump < 0) {
1178			fprintf(stderr, "socket_coredump_signal_sigabrt: accept4 failed: %m\n");
1179			goto out;
1180		}
1181
1182		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1183		if (fd_peer_pidfd < 0) {
1184			fprintf(stderr, "socket_coredump_signal_sigabrt: get_peer_pidfd failed\n");
1185			goto out;
1186		}
1187
1188		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1189			fprintf(stderr, "socket_coredump_signal_sigabrt: get_pidfd_info failed\n");
1190			goto out;
1191		}
1192
1193		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1194			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP not set in mask\n");
1195			goto out;
1196		}
1197
1198		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1199			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_COREDUMPED not set in coredump_mask\n");
1200			goto out;
1201		}
1202
1203		/* Verify coredump_signal is available and correct */
1204		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
1205			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
1206			goto out;
1207		}
1208
1209		if (info.coredump_signal != SIGABRT) {
1210			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_signal=%d, expected SIGABRT=%d\n",
1211				info.coredump_signal, SIGABRT);
1212			goto out;
1213		}
1214
1215		if (!read_coredump_req(fd_coredump, &req)) {
1216			fprintf(stderr, "socket_coredump_signal_sigabrt: read_coredump_req failed\n");
1217			goto out;
1218		}
1219
1220		if (!send_coredump_ack(fd_coredump, &req,
1221				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
1222			fprintf(stderr, "socket_coredump_signal_sigabrt: send_coredump_ack failed\n");
1223			goto out;
1224		}
1225
1226		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1227			fprintf(stderr, "socket_coredump_signal_sigabrt: read_marker COREDUMP_MARK_REQACK failed\n");
1228			goto out;
1229		}
1230
1231		exit_code = EXIT_SUCCESS;
1232		fprintf(stderr, "socket_coredump_signal_sigabrt: completed successfully\n");
1233out:
1234		if (fd_peer_pidfd >= 0)
1235			close(fd_peer_pidfd);
1236		if (fd_coredump >= 0)
1237			close(fd_coredump);
1238		if (fd_server >= 0)
1239			close(fd_server);
1240		_exit(exit_code);
1241	}
1242	self->pid_coredump_server = pid_coredump_server;
1243
1244	EXPECT_EQ(close(ipc_sockets[1]), 0);
1245	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1246	EXPECT_EQ(close(ipc_sockets[0]), 0);
1247
1248	pid = fork();
1249	ASSERT_GE(pid, 0);
1250	if (pid == 0)
1251		abort();
1252
1253	pidfd = sys_pidfd_open(pid, 0);
1254	ASSERT_GE(pidfd, 0);
1255
1256	waitpid(pid, &status, 0);
1257	ASSERT_TRUE(WIFSIGNALED(status));
1258	ASSERT_EQ(WTERMSIG(status), SIGABRT);
1259
1260	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1261	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
1262	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
1263	ASSERT_EQ(info.coredump_signal, SIGABRT);
1264
1265	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1266}
1267
1268TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500)
1269{
1270	int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1271	pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server;
1272	struct pidfd_info info = {};
1273	int ipc_sockets[2];
1274	char c;
1275
1276	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1277
1278	ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1279
1280	pid_coredump_server = fork();
1281	ASSERT_GE(pid_coredump_server, 0);
1282	if (pid_coredump_server == 0) {
1283		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1284		int exit_code = EXIT_FAILURE;
1285		struct coredump_req req = {};
1286
1287		close(ipc_sockets[0]);
1288		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1289		if (fd_server < 0) {
1290			fprintf(stderr, "Failed to create and listen on unix socket\n");
1291			goto out;
1292		}
1293
1294		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1295			fprintf(stderr, "Failed to notify parent via ipc socket\n");
1296			goto out;
1297		}
1298		close(ipc_sockets[1]);
1299
1300		for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1301			fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1302			if (fd_coredump < 0) {
1303				fprintf(stderr, "accept4 failed: %m\n");
1304				goto out;
1305			}
1306
1307			fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1308			if (fd_peer_pidfd < 0) {
1309				fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump);
1310				goto out;
1311			}
1312
1313			if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1314				fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd);
1315				goto out;
1316			}
1317
1318			if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1319				fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd);
1320				goto out;
1321			}
1322			if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1323				fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd);
1324				goto out;
1325			}
1326
1327			if (!read_coredump_req(fd_coredump, &req)) {
1328				fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump);
1329				goto out;
1330			}
1331
1332			if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1333						COREDUMP_KERNEL | COREDUMP_USERSPACE |
1334						COREDUMP_REJECT | COREDUMP_WAIT)) {
1335				fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump);
1336				goto out;
1337			}
1338
1339			if (!send_coredump_ack(fd_coredump, &req,
1340					       COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1341				fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump);
1342				goto out;
1343			}
1344
1345			if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1346				fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump);
1347				goto out;
1348			}
1349
1350			fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1351			if (fd_core_file < 0) {
1352				fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump);
1353				goto out;
1354			}
1355
1356			for (;;) {
1357				char buffer[4096];
1358				ssize_t bytes_read, bytes_write;
1359
1360				bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1361				if (bytes_read < 0) {
1362					fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump);
1363					goto out;
1364				}
1365
1366				if (bytes_read == 0)
1367					break;
1368
1369				bytes_write = write(fd_core_file, buffer, bytes_read);
1370				if (bytes_read != bytes_write) {
1371					if (bytes_write < 0 && errno == ENOSPC)
1372						continue;
1373					fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file);
1374					goto out;
1375				}
1376			}
1377
1378			close(fd_core_file);
1379			close(fd_peer_pidfd);
1380			close(fd_coredump);
1381			fd_peer_pidfd = -1;
1382			fd_coredump = -1;
1383		}
1384
1385		exit_code = EXIT_SUCCESS;
1386out:
1387		if (fd_core_file >= 0)
1388			close(fd_core_file);
1389		if (fd_peer_pidfd >= 0)
1390			close(fd_peer_pidfd);
1391		if (fd_coredump >= 0)
1392			close(fd_coredump);
1393		if (fd_server >= 0)
1394			close(fd_server);
1395		_exit(exit_code);
1396	}
1397	self->pid_coredump_server = pid_coredump_server;
1398
1399	EXPECT_EQ(close(ipc_sockets[1]), 0);
1400	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1401	EXPECT_EQ(close(ipc_sockets[0]), 0);
1402
1403	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1404		pid[i] = fork();
1405		ASSERT_GE(pid[i], 0);
1406		if (pid[i] == 0)
1407			crashing_child();
1408		pidfd[i] = sys_pidfd_open(pid[i], 0);
1409		ASSERT_GE(pidfd[i], 0);
1410	}
1411
1412	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1413		waitpid(pid[i], &status[i], 0);
1414		ASSERT_TRUE(WIFSIGNALED(status[i]));
1415		ASSERT_TRUE(WCOREDUMP(status[i]));
1416	}
1417
1418	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1419		info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1420		ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1421		ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1422		ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1423	}
1424
1425	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1426}
1427
1428TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500)
1429{
1430	int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1431	pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS];
1432	struct pidfd_info info = {};
1433	int ipc_sockets[2];
1434	char c;
1435
1436	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1437	ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1438
1439	pid_coredump_server = fork();
1440	ASSERT_GE(pid_coredump_server, 0);
1441	if (pid_coredump_server == 0) {
1442		int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0;
1443		fd_server = -1;
1444		exit_code = EXIT_FAILURE;
1445		n_conns = 0;
1446		close(ipc_sockets[0]);
1447		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1448		if (fd_server < 0) {
1449			fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: create_and_listen_unix_socket failed: %m\n");
1450			goto out;
1451		}
1452
1453		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1454			fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: write_nointr to ipc socket failed: %m\n");
1455			goto out;
1456		}
1457		close(ipc_sockets[1]);
1458
1459		while (n_conns < NUM_CRASHING_COREDUMPS) {
1460			int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1461			struct coredump_req req = {};
1462			fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1463			if (fd_coredump < 0) {
1464				if (errno == EAGAIN || errno == EWOULDBLOCK)
1465					continue;
1466				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: accept4 failed: %m\n");
1467				goto out;
1468			}
1469			fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1470			if (fd_peer_pidfd < 0) {
1471				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: get_peer_pidfd failed\n");
1472				goto out;
1473			}
1474			if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1475				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: get_pidfd_info failed\n");
1476				goto out;
1477			}
1478			if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) {
1479				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: missing PIDFD_INFO_COREDUMP or PIDFD_COREDUMPED\n");
1480				goto out;
1481			}
1482			if (!read_coredump_req(fd_coredump, &req)) {
1483				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: read_coredump_req failed\n");
1484				goto out;
1485			}
1486			if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1487						COREDUMP_KERNEL | COREDUMP_USERSPACE |
1488						COREDUMP_REJECT | COREDUMP_WAIT)) {
1489				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: check_coredump_req failed\n");
1490				goto out;
1491			}
1492			if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1493				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: send_coredump_ack failed\n");
1494				goto out;
1495			}
1496			if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1497				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: read_marker failed\n");
1498				goto out;
1499			}
1500			fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1501			if (fd_core_file < 0) {
1502				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: open_coredump_tmpfile failed: %m\n");
1503				goto out;
1504			}
1505			pid_t worker = fork();
1506			if (worker == 0) {
1507				close(fd_server);
1508				process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file);
1509			}
1510			worker_pids[n_conns] = worker;
1511			if (fd_coredump >= 0)
1512				close(fd_coredump);
1513			if (fd_peer_pidfd >= 0)
1514				close(fd_peer_pidfd);
1515			if (fd_core_file >= 0)
1516				close(fd_core_file);
1517			n_conns++;
1518		}
1519		exit_code = EXIT_SUCCESS;
1520out:
1521		if (fd_server >= 0)
1522			close(fd_server);
1523
1524		// Reap all worker processes
1525		for (int i = 0; i < n_conns; i++) {
1526			int wstatus;
1527			if (waitpid(worker_pids[i], &wstatus, 0) < 0) {
1528				fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]);
1529			} else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) {
1530				fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus));
1531				exit_code = EXIT_FAILURE;
1532			}
1533		}
1534
1535		_exit(exit_code);
1536	}
1537	self->pid_coredump_server = pid_coredump_server;
1538
1539	EXPECT_EQ(close(ipc_sockets[1]), 0);
1540	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1541	EXPECT_EQ(close(ipc_sockets[0]), 0);
1542
1543	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1544		pid[i] = fork();
1545		ASSERT_GE(pid[i], 0);
1546		if (pid[i] == 0)
1547			crashing_child();
1548		pidfd[i] = sys_pidfd_open(pid[i], 0);
1549		ASSERT_GE(pidfd[i], 0);
1550	}
1551
1552	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1553		ASSERT_GE(waitpid(pid[i], &status[i], 0), 0);
1554		ASSERT_TRUE(WIFSIGNALED(status[i]));
1555		ASSERT_TRUE(WCOREDUMP(status[i]));
1556	}
1557
1558	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1559		info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1560		ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1561		ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1562		ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1563	}
1564
1565	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1566}
1567
1568TEST_HARNESS_MAIN
~/ Read-only file preview.