1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 #define _GNU_SOURCE
3 #include <error.h>
4 #include <limits.h>
5 #include <stddef.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/socket.h>
9 #include <linux/socket.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <pthread.h>
14 #include <sys/un.h>
15 #include <sys/signal.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18
19 #include "../../pidfd/pidfd.h"
20 #include "kselftest_harness.h"
21
22 #define clean_errno() (errno == 0 ? "None" : strerror(errno))
23 #define log_err(MSG, ...) \
24 fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \
25 clean_errno(), ##__VA_ARGS__)
26
27 #ifndef SCM_PIDFD
28 #define SCM_PIDFD 0x04
29 #endif
30
31 #ifndef SCM_PIDFD_THREAD
32 #define SCM_PIDFD_THREAD 0x05
33 #endif
34
35 #ifndef SO_PASSPIDFD_THREAD
36 #define SO_PASSPIDFD_THREAD 86
37 #endif
38
39 #ifndef SO_PEERPIDFD_THREAD
40 #define SO_PEERPIDFD_THREAD 87
41 #endif
42
43 #define CHILD_EXIT_CODE_OK 123
44
child_die()45 static void child_die()
46 {
47 exit(1);
48 }
49
safe_int(const char * numstr,int * converted)50 static int safe_int(const char *numstr, int *converted)
51 {
52 char *err = NULL;
53 long sli;
54
55 errno = 0;
56 sli = strtol(numstr, &err, 0);
57 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
58 return -ERANGE;
59
60 if (errno != 0 && sli == 0)
61 return -EINVAL;
62
63 if (err == numstr || *err != '\0')
64 return -EINVAL;
65
66 if (sli > INT_MAX || sli < INT_MIN)
67 return -ERANGE;
68
69 *converted = (int)sli;
70 return 0;
71 }
72
char_left_gc(const char * buffer,size_t len)73 static int char_left_gc(const char *buffer, size_t len)
74 {
75 size_t i;
76
77 for (i = 0; i < len; i++) {
78 if (buffer[i] == ' ' || buffer[i] == '\t')
79 continue;
80
81 return i;
82 }
83
84 return 0;
85 }
86
char_right_gc(const char * buffer,size_t len)87 static int char_right_gc(const char *buffer, size_t len)
88 {
89 int i;
90
91 for (i = len - 1; i >= 0; i--) {
92 if (buffer[i] == ' ' || buffer[i] == '\t' ||
93 buffer[i] == '\n' || buffer[i] == '\0')
94 continue;
95
96 return i + 1;
97 }
98
99 return 0;
100 }
101
trim_whitespace_in_place(char * buffer)102 static char *trim_whitespace_in_place(char *buffer)
103 {
104 buffer += char_left_gc(buffer, strlen(buffer));
105 buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
106 return buffer;
107 }
108
109 /* borrowed (with all helpers) from pidfd/pidfd_open_test.c */
get_pid_from_fdinfo_file(int pidfd,const char * key,size_t keylen)110 static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
111 {
112 int ret;
113 char path[512];
114 FILE *f;
115 size_t n = 0;
116 pid_t result = -1;
117 char *line = NULL;
118
119 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
120
121 f = fopen(path, "re");
122 if (!f)
123 return -1;
124
125 while (getline(&line, &n, f) != -1) {
126 char *numstr;
127
128 if (strncmp(line, key, keylen))
129 continue;
130
131 numstr = trim_whitespace_in_place(line + 4);
132 ret = safe_int(numstr, &result);
133 if (ret < 0)
134 goto out;
135
136 break;
137 }
138
139 out:
140 free(line);
141 fclose(f);
142 return result;
143 }
144
145 struct cmsg_data {
146 struct ucred *ucred;
147 int *pidfd;
148 };
149
parse_cmsg(struct msghdr * msg,struct cmsg_data * res)150 static int parse_cmsg(struct msghdr *msg, struct cmsg_data *res)
151 {
152 struct cmsghdr *cmsg;
153
154 if (msg->msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
155 log_err("recvmsg: truncated");
156 return 1;
157 }
158
159 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
160 cmsg = CMSG_NXTHDR(msg, cmsg)) {
161 if (cmsg->cmsg_level == SOL_SOCKET &&
162 cmsg->cmsg_type == SCM_PIDFD) {
163 if (cmsg->cmsg_len < sizeof(*res->pidfd)) {
164 log_err("CMSG parse: SCM_PIDFD wrong len");
165 return 1;
166 }
167
168 res->pidfd = (void *)CMSG_DATA(cmsg);
169 }
170
171 if (cmsg->cmsg_level == SOL_SOCKET &&
172 cmsg->cmsg_type == SCM_CREDENTIALS) {
173 if (cmsg->cmsg_len < sizeof(*res->ucred)) {
174 log_err("CMSG parse: SCM_CREDENTIALS wrong len");
175 return 1;
176 }
177
178 res->ucred = (void *)CMSG_DATA(cmsg);
179 }
180 }
181
182 if (!res->pidfd) {
183 log_err("CMSG parse: SCM_PIDFD not found");
184 return 1;
185 }
186
187 if (!res->ucred) {
188 log_err("CMSG parse: SCM_CREDENTIALS not found");
189 return 1;
190 }
191
192 return 0;
193 }
194
cmsg_check(int fd)195 static int cmsg_check(int fd)
196 {
197 struct msghdr msg = { 0 };
198 struct cmsg_data res;
199 struct iovec iov;
200 int data = 0;
201 char control[CMSG_SPACE(sizeof(struct ucred)) +
202 CMSG_SPACE(sizeof(int))] = { 0 };
203 pid_t parent_pid;
204 int err;
205
206 iov.iov_base = &data;
207 iov.iov_len = sizeof(data);
208
209 msg.msg_iov = &iov;
210 msg.msg_iovlen = 1;
211 msg.msg_control = control;
212 msg.msg_controllen = sizeof(control);
213
214 err = recvmsg(fd, &msg, 0);
215 if (err < 0) {
216 log_err("recvmsg");
217 return 1;
218 }
219
220 if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
221 log_err("recvmsg: truncated");
222 return 1;
223 }
224
225 /* send(pfd, "x", sizeof(char), 0) */
226 if (data != 'x') {
227 log_err("recvmsg: data corruption");
228 return 1;
229 }
230
231 if (parse_cmsg(&msg, &res)) {
232 log_err("CMSG parse: parse_cmsg() failed");
233 return 1;
234 }
235
236 /* pidfd from SCM_PIDFD should point to the parent process PID */
237 parent_pid =
238 get_pid_from_fdinfo_file(*res.pidfd, "Pid:", sizeof("Pid:") - 1);
239 if (parent_pid != getppid()) {
240 log_err("wrong SCM_PIDFD %d != %d", parent_pid, getppid());
241 close(*res.pidfd);
242 return 1;
243 }
244
245 close(*res.pidfd);
246 return 0;
247 }
248
cmsg_check_dead(int fd,int expected_pid)249 static int cmsg_check_dead(int fd, int expected_pid)
250 {
251 int err;
252 struct msghdr msg = { 0 };
253 struct cmsg_data res;
254 struct iovec iov;
255 int data = 0;
256 char control[CMSG_SPACE(sizeof(struct ucred)) +
257 CMSG_SPACE(sizeof(int))] = { 0 };
258 struct pidfd_info info = {
259 .mask = PIDFD_INFO_EXIT,
260 };
261
262 iov.iov_base = &data;
263 iov.iov_len = sizeof(data);
264
265 msg.msg_iov = &iov;
266 msg.msg_iovlen = 1;
267 msg.msg_control = control;
268 msg.msg_controllen = sizeof(control);
269
270 err = recvmsg(fd, &msg, 0);
271 if (err < 0) {
272 log_err("recvmsg");
273 return 1;
274 }
275
276 if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
277 log_err("recvmsg: truncated");
278 return 1;
279 }
280
281 /* send(cfd, "y", sizeof(char), 0) */
282 if (data != 'y') {
283 log_err("recvmsg: data corruption");
284 return 1;
285 }
286
287 if (parse_cmsg(&msg, &res)) {
288 log_err("CMSG parse: parse_cmsg() failed");
289 return 1;
290 }
291
292 /*
293 * pidfd from SCM_PIDFD should point to the client_pid.
294 * Let's read exit information and check if it's what
295 * we expect to see.
296 */
297 if (ioctl(*res.pidfd, PIDFD_GET_INFO, &info)) {
298 log_err("%s: ioctl(PIDFD_GET_INFO) failed", __func__);
299 close(*res.pidfd);
300 return 1;
301 }
302
303 if (!(info.mask & PIDFD_INFO_EXIT)) {
304 log_err("%s: No exit information from ioctl(PIDFD_GET_INFO)", __func__);
305 close(*res.pidfd);
306 return 1;
307 }
308
309 err = WIFEXITED(info.exit_code) ? WEXITSTATUS(info.exit_code) : 1;
310 if (err != CHILD_EXIT_CODE_OK) {
311 log_err("%s: wrong exit_code %d != %d", __func__, err, CHILD_EXIT_CODE_OK);
312 close(*res.pidfd);
313 return 1;
314 }
315
316 close(*res.pidfd);
317 return 0;
318 }
319
320 struct sock_addr {
321 char sock_name[32];
322 struct sockaddr_un listen_addr;
323 socklen_t addrlen;
324 };
325
FIXTURE(scm_pidfd)326 FIXTURE(scm_pidfd)
327 {
328 int server;
329 pid_t client_pid;
330 int startup_pipe[2];
331 struct sock_addr server_addr;
332 struct sock_addr *client_addr;
333 };
334
FIXTURE_VARIANT(scm_pidfd)335 FIXTURE_VARIANT(scm_pidfd)
336 {
337 int type;
338 bool abstract;
339 };
340
FIXTURE_VARIANT_ADD(scm_pidfd,stream_pathname)341 FIXTURE_VARIANT_ADD(scm_pidfd, stream_pathname)
342 {
343 .type = SOCK_STREAM,
344 .abstract = 0,
345 };
346
FIXTURE_VARIANT_ADD(scm_pidfd,stream_abstract)347 FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract)
348 {
349 .type = SOCK_STREAM,
350 .abstract = 1,
351 };
352
FIXTURE_VARIANT_ADD(scm_pidfd,dgram_pathname)353 FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname)
354 {
355 .type = SOCK_DGRAM,
356 .abstract = 0,
357 };
358
FIXTURE_VARIANT_ADD(scm_pidfd,dgram_abstract)359 FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract)
360 {
361 .type = SOCK_DGRAM,
362 .abstract = 1,
363 };
364
FIXTURE_SETUP(scm_pidfd)365 FIXTURE_SETUP(scm_pidfd)
366 {
367 self->client_addr = mmap(NULL, sizeof(*self->client_addr), PROT_READ | PROT_WRITE,
368 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
369 ASSERT_NE(MAP_FAILED, self->client_addr);
370 }
371
FIXTURE_TEARDOWN(scm_pidfd)372 FIXTURE_TEARDOWN(scm_pidfd)
373 {
374 close(self->server);
375
376 kill(self->client_pid, SIGKILL);
377 waitpid(self->client_pid, NULL, 0);
378
379 if (!variant->abstract) {
380 unlink(self->server_addr.sock_name);
381 unlink(self->client_addr->sock_name);
382 }
383 }
384
fill_sockaddr(struct sock_addr * addr,bool abstract)385 static void fill_sockaddr(struct sock_addr *addr, bool abstract)
386 {
387 char *sun_path_buf = (char *)&addr->listen_addr.sun_path;
388
389 addr->listen_addr.sun_family = AF_UNIX;
390 addr->addrlen = offsetof(struct sockaddr_un, sun_path);
391 snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid());
392 addr->addrlen += strlen(addr->sock_name);
393 if (abstract) {
394 *sun_path_buf = '\0';
395 addr->addrlen++;
396 sun_path_buf++;
397 } else {
398 unlink(addr->sock_name);
399 }
400 memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name));
401 }
402
sk_enable_cred_pass(int sk)403 static int sk_enable_cred_pass(int sk)
404 {
405 int on = 0;
406
407 on = 1;
408 if (setsockopt(sk, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
409 log_err("Failed to set SO_PASSCRED");
410 return 1;
411 }
412
413 if (setsockopt(sk, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
414 log_err("Failed to set SO_PASSPIDFD");
415 return 1;
416 }
417
418 return 0;
419 }
420
client(FIXTURE_DATA (scm_pidfd)* self,const FIXTURE_VARIANT (scm_pidfd)* variant)421 static void client(FIXTURE_DATA(scm_pidfd) *self,
422 const FIXTURE_VARIANT(scm_pidfd) *variant)
423 {
424 int cfd;
425 socklen_t len;
426 struct ucred peer_cred;
427 int peer_pidfd;
428 pid_t peer_pid;
429
430 cfd = socket(AF_UNIX, variant->type, 0);
431 if (cfd < 0) {
432 log_err("socket");
433 child_die();
434 }
435
436 if (variant->type == SOCK_DGRAM) {
437 fill_sockaddr(self->client_addr, variant->abstract);
438
439 if (bind(cfd, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen)) {
440 log_err("bind");
441 child_die();
442 }
443 }
444
445 if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr,
446 self->server_addr.addrlen) != 0) {
447 log_err("connect");
448 child_die();
449 }
450
451 if (sk_enable_cred_pass(cfd)) {
452 log_err("sk_enable_cred_pass() failed");
453 child_die();
454 }
455
456 close(self->startup_pipe[1]);
457
458 if (cmsg_check(cfd)) {
459 log_err("cmsg_check failed");
460 child_die();
461 }
462
463 /* send something to the parent so it can receive SCM_PIDFD too and validate it */
464 if (send(cfd, "y", sizeof(char), 0) == -1) {
465 log_err("Failed to send(cfd, \"y\", sizeof(char), 0)");
466 child_die();
467 }
468
469 /* skip further for SOCK_DGRAM as it's not applicable */
470 if (variant->type == SOCK_DGRAM)
471 return;
472
473 len = sizeof(peer_cred);
474 if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) {
475 log_err("Failed to get SO_PEERCRED");
476 child_die();
477 }
478
479 len = sizeof(peer_pidfd);
480 if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) {
481 log_err("Failed to get SO_PEERPIDFD");
482 child_die();
483 }
484
485 /* pid from SO_PEERCRED should point to the parent process PID */
486 if (peer_cred.pid != getppid()) {
487 log_err("peer_cred.pid != getppid(): %d != %d", peer_cred.pid, getppid());
488 child_die();
489 }
490
491 peer_pid = get_pid_from_fdinfo_file(peer_pidfd,
492 "Pid:", sizeof("Pid:") - 1);
493 if (peer_pid != peer_cred.pid) {
494 log_err("peer_pid != peer_cred.pid: %d != %d", peer_pid, peer_cred.pid);
495 child_die();
496 }
497 }
498
TEST_F(scm_pidfd,test)499 TEST_F(scm_pidfd, test)
500 {
501 int err;
502 int pfd;
503 int child_status = 0;
504
505 self->server = socket(AF_UNIX, variant->type, 0);
506 ASSERT_NE(-1, self->server);
507
508 fill_sockaddr(&self->server_addr, variant->abstract);
509
510 err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen);
511 ASSERT_EQ(0, err);
512
513 if (variant->type == SOCK_STREAM) {
514 err = listen(self->server, 1);
515 ASSERT_EQ(0, err);
516 }
517
518 err = pipe(self->startup_pipe);
519 ASSERT_NE(-1, err);
520
521 self->client_pid = fork();
522 ASSERT_NE(-1, self->client_pid);
523 if (self->client_pid == 0) {
524 close(self->server);
525 close(self->startup_pipe[0]);
526 client(self, variant);
527
528 /*
529 * It's a bit unusual, but in case of success we return non-zero
530 * exit code (CHILD_EXIT_CODE_OK) and then we expect to read it
531 * from ioctl(PIDFD_GET_INFO) in cmsg_check_dead().
532 */
533 exit(CHILD_EXIT_CODE_OK);
534 }
535 close(self->startup_pipe[1]);
536
537 if (variant->type == SOCK_STREAM) {
538 pfd = accept(self->server, NULL, NULL);
539 ASSERT_NE(-1, pfd);
540 } else {
541 pfd = self->server;
542 }
543
544 /* wait until the child arrives at checkpoint */
545 read(self->startup_pipe[0], &err, sizeof(int));
546 close(self->startup_pipe[0]);
547
548 if (variant->type == SOCK_DGRAM) {
549 err = sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen);
550 ASSERT_NE(-1, err);
551 } else {
552 err = send(pfd, "x", sizeof(char), 0);
553 ASSERT_NE(-1, err);
554 }
555
556 waitpid(self->client_pid, &child_status, 0);
557 /* see comment before exit(CHILD_EXIT_CODE_OK) */
558 ASSERT_EQ(CHILD_EXIT_CODE_OK, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1);
559
560 err = sk_enable_cred_pass(pfd);
561 ASSERT_EQ(0, err);
562
563 err = cmsg_check_dead(pfd, self->client_pid);
564 ASSERT_EQ(0, err);
565
566 close(pfd);
567 }
568
569 struct thread_ids {
570 pid_t pid;
571 pid_t tid;
572 };
573
574 #define MAX_WRITERS 2
575
576 /* Used by writers to signal they've written, so we can sequence multiple writers */
577 static int seq_pipe[2];
578
send_ids_thread(void * arg)579 static void *send_ids_thread(void *arg)
580 {
581 int fd = *(int *)arg;
582 struct thread_ids ids = {
583 .pid = getpid(),
584 .tid = gettid(),
585 };
586 char sync;
587
588 if (send(fd, &ids, sizeof(ids), 0) != sizeof(ids))
589 return (void *)1;
590
591 /* let the client start the next writer, so the queue order is known */
592 if (write(seq_pipe[1], "1", 1) != 1)
593 return (void *)1;
594
595 /* stay alive until the receiver has looked at our pidfd */
596 if (read(fd, &sync, 1) != 1)
597 return (void *)1;
598
599 return NULL;
600 }
601
send_ids_creds_thread(void * arg)602 static void *send_ids_creds_thread(void *arg)
603 {
604 int fd = *(int *)arg;
605 struct thread_ids ids = {
606 .pid = getpid(),
607 .tid = gettid(),
608 };
609 struct ucred ucred = {
610 .pid = getpid(),
611 .uid = getuid(),
612 .gid = getgid(),
613 };
614 char control[CMSG_SPACE(sizeof(ucred))] = { 0 };
615 struct iovec iov;
616 struct msghdr msg = { 0 };
617 struct cmsghdr *cmsg;
618 char sync;
619
620 iov.iov_base = &ids;
621 iov.iov_len = sizeof(ids);
622
623 msg.msg_iov = &iov;
624 msg.msg_iovlen = 1;
625 msg.msg_control = control;
626 msg.msg_controllen = sizeof(control);
627
628 cmsg = CMSG_FIRSTHDR(&msg);
629 cmsg->cmsg_level = SOL_SOCKET;
630 cmsg->cmsg_type = SCM_CREDENTIALS;
631 cmsg->cmsg_len = CMSG_LEN(sizeof(ucred));
632 memcpy(CMSG_DATA(cmsg), &ucred, sizeof(ucred));
633
634 if (sendmsg(fd, &msg, 0) != sizeof(ids))
635 return (void *)1;
636
637 /* signal we've written our info */
638 if (write(seq_pipe[1], "1", 1) != 1)
639 return (void *)1;
640
641 /* stay alive until the receiver has looked at our pidfd */
642 if (read(fd, &sync, 1) != 1)
643 return (void *)1;
644
645 return NULL;
646 }
647
648 /*
649 * Runs @nwriters copies of @sender, each in its own non-leader thread, one
650 * at a time so the queue order is known, then tells the parent on @ackfd
651 * that everything is queued.
652 */
thread_client(int fd,int syncfd,int ackfd,void * (* sender)(void *),int nwriters)653 static void thread_client(int fd, int syncfd, int ackfd,
654 void *(*sender)(void *), int nwriters)
655 {
656 pthread_t writers[MAX_WRITERS];
657 void *ret;
658 char sync;
659 int i;
660
661 /* wait until the receiver enabled the options it wants */
662 if (read(syncfd, &sync, 1) != 1)
663 child_die();
664
665 for (i = 0; i < nwriters; i++) {
666 if (pthread_create(&writers[i], NULL, sender, &fd))
667 child_die();
668
669 if (read(seq_pipe[0], &sync, 1) != 1)
670 child_die();
671 }
672
673 if (write(ackfd, "1", 1) != 1)
674 child_die();
675
676 for (i = 0; i < nwriters; i++)
677 if (pthread_join(writers[i], &ret) || ret)
678 child_die();
679
680 exit(0);
681 }
682
683 struct pidfd_msg {
684 ssize_t len;
685 struct thread_ids ids;
686 struct pidfd_info tgid_info;
687 struct pidfd_info thread_info;
688 int tgid_flags;
689 int thread_flags;
690 bool have_tgid;
691 bool have_thread;
692 };
693
get_pidfd_info(int pidfd,struct pidfd_info * info)694 static int get_pidfd_info(int pidfd, struct pidfd_info *info)
695 {
696 info->mask = PIDFD_INFO_PID;
697 if (ioctl(pidfd, PIDFD_GET_INFO, info)) {
698 log_err("ioctl(PIDFD_GET_INFO)");
699 return -1;
700 }
701
702 return 0;
703 }
704
705 /* One recvmsg(), reporting how many bytes came back and what the pidfd
706 * cmsgs that came with them say.
707 */
read_pidfd_msg(int fd,struct pidfd_msg * out)708 static int read_pidfd_msg(int fd, struct pidfd_msg *out)
709 {
710 char control[CMSG_SPACE(sizeof(int)) * 2] = { 0 };
711 int tgid_pidfd = -1, thread_pidfd = -1;
712 struct thread_ids buf[2] = { 0 };
713 struct msghdr msg = { 0 };
714 struct cmsghdr *cmsg;
715 struct iovec iov;
716
717 iov.iov_base = buf;
718 iov.iov_len = sizeof(buf);
719 msg.msg_iov = &iov;
720 msg.msg_iovlen = 1;
721 msg.msg_control = control;
722 msg.msg_controllen = sizeof(control);
723
724 out->len = recvmsg(fd, &msg, 0);
725 if (out->len < 0) {
726 log_err("recvmsg");
727 return -1;
728 }
729
730 if (msg.msg_flags & MSG_CTRUNC) {
731 log_err("recvmsg: control truncated");
732 return -1;
733 }
734
735 out->ids = buf[0];
736
737 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
738 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
739 if (cmsg->cmsg_level != SOL_SOCKET)
740 continue;
741
742 if (cmsg->cmsg_type == SCM_PIDFD)
743 memcpy(&tgid_pidfd, CMSG_DATA(cmsg), sizeof(tgid_pidfd));
744 else if (cmsg->cmsg_type == SCM_PIDFD_THREAD)
745 memcpy(&thread_pidfd, CMSG_DATA(cmsg), sizeof(thread_pidfd));
746 }
747
748 out->have_tgid = tgid_pidfd >= 0;
749 out->have_thread = thread_pidfd >= 0;
750
751 if (out->have_tgid) {
752 if (get_pidfd_info(tgid_pidfd, &out->tgid_info))
753 return -1;
754 out->tgid_flags = fcntl(tgid_pidfd, F_GETFL);
755 close(tgid_pidfd);
756 }
757
758 if (out->have_thread) {
759 if (get_pidfd_info(thread_pidfd, &out->thread_info))
760 return -1;
761 out->thread_flags = fcntl(thread_pidfd, F_GETFL);
762 close(thread_pidfd);
763 }
764
765 return 0;
766 }
767
768 /*
769 * Runs @nwriters threads of one child process against a SOCK_STREAM pair,
770 * all of them queued before the parent reads. SO_PASSPIDFD is set when
771 * @want_tgid is given, SO_PASSPIDFD_THREAD when @want_thread is. @nread
772 * reads are returned in @out.
773 */
pidfd_flow(void * (* sender)(void *),int nwriters,bool want_tgid,bool want_thread,struct pidfd_msg * out,int nread)774 static int pidfd_flow(void *(*sender)(void *), int nwriters, bool want_tgid,
775 bool want_thread, struct pidfd_msg *out, int nread)
776 {
777 int child_status = 0;
778 int syncpipe[2];
779 int ackpipe[2];
780 int sk[2];
781 int on = 1;
782 char sync;
783 pid_t child;
784 int i;
785
786 if (nwriters > MAX_WRITERS)
787 return -1;
788
789 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sk))
790 return -1;
791 if (pipe(syncpipe) || pipe(ackpipe) || pipe(seq_pipe))
792 return -1;
793
794 child = fork();
795 if (child < 0)
796 return -1;
797
798 if (child == 0) {
799 close(sk[0]);
800 close(syncpipe[1]);
801 close(ackpipe[0]);
802 thread_client(sk[1], syncpipe[0], ackpipe[1], sender, nwriters);
803 }
804 close(sk[1]);
805 close(syncpipe[0]);
806 close(ackpipe[1]);
807 close(seq_pipe[0]);
808 close(seq_pipe[1]);
809
810 if (want_tgid &&
811 setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
812 log_err("Failed to set SO_PASSPIDFD");
813 return -1;
814 }
815
816 if (want_thread &&
817 setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD_THREAD, &on, sizeof(on))) {
818 log_err("Failed to set SO_PASSPIDFD_THREAD");
819 return -1;
820 }
821
822 /* let the child know the options are set, it can write now */
823 if (write(syncpipe[1], "1", 1) != 1)
824 return -1;
825 close(syncpipe[1]);
826
827 /* wait until every writer has queued its message */
828 if (read(ackpipe[0], &sync, 1) != 1)
829 return -1;
830 close(ackpipe[0]);
831
832 for (i = 0; i < nread; i++)
833 if (read_pidfd_msg(sk[0], &out[i]))
834 return -1;
835
836 /* release the writers */
837 for (i = 0; i < nwriters; i++)
838 if (write(sk[0], "x", 1) != 1)
839 return -1;
840 close(sk[0]);
841
842 waitpid(child, &child_status, 0);
843 if (!WIFEXITED(child_status) || WEXITSTATUS(child_status))
844 return -1;
845
846 return 0;
847 }
848
sockopt_set(int fd,int optname,int val)849 static int sockopt_set(int fd, int optname, int val)
850 {
851 return setsockopt(fd, SOL_SOCKET, optname, &val, sizeof(val));
852 }
853
sockopt_get(int fd,int optname)854 static int sockopt_get(int fd, int optname)
855 {
856 socklen_t len = sizeof(int);
857 int val = -1;
858
859 if (getsockopt(fd, SOL_SOCKET, optname, &val, &len))
860 return -1;
861
862 return val;
863 }
864
TEST(scm_pidfd_setsockopt_values)865 TEST(scm_pidfd_setsockopt_values)
866 {
867 int sk[2];
868
869 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sk));
870
871 /* Verify that the options are truly set independently */
872 ASSERT_EQ(0, sockopt_set(sk[0], SO_PASSPIDFD_THREAD, 1));
873 ASSERT_EQ(1, sockopt_get(sk[0], SO_PASSPIDFD_THREAD));
874 ASSERT_EQ(0, sockopt_get(sk[0], SO_PASSPIDFD));
875
876 ASSERT_EQ(0, sockopt_set(sk[0], SO_PASSPIDFD, 1));
877 ASSERT_EQ(1, sockopt_get(sk[0], SO_PASSPIDFD));
878 ASSERT_EQ(1, sockopt_get(sk[0], SO_PASSPIDFD_THREAD));
879
880 /* Verify that the options are truly cleared independently */
881 ASSERT_EQ(0, sockopt_set(sk[0], SO_PASSPIDFD, 0));
882 ASSERT_EQ(0, sockopt_get(sk[0], SO_PASSPIDFD));
883 ASSERT_EQ(1, sockopt_get(sk[0], SO_PASSPIDFD_THREAD));
884
885 ASSERT_EQ(0, sockopt_set(sk[0], SO_PASSPIDFD_THREAD, 0));
886 ASSERT_EQ(0, sockopt_get(sk[0], SO_PASSPIDFD_THREAD));
887 ASSERT_EQ(0, sockopt_get(sk[0], SO_PASSPIDFD));
888
889 close(sk[0]);
890 close(sk[1]);
891 }
892
893 /* A receiver that only asked about the process cannot tell the two
894 * threads apart, so their writes are glued into one read.
895 */
TEST(scm_pidfd_stream_glues_threads)896 TEST(scm_pidfd_stream_glues_threads)
897 {
898 struct pidfd_msg msg[1] = { 0 };
899
900 ASSERT_EQ(0, pidfd_flow(send_ids_thread, 2, true, false, msg, 1));
901 EXPECT_EQ(sizeof(struct thread_ids) * 2, msg[0].len);
902
903 EXPECT_TRUE(msg[0].have_tgid);
904 EXPECT_FALSE(msg[0].have_thread);
905 EXPECT_EQ(msg[0].ids.pid, msg[0].tgid_info.pid);
906 EXPECT_EQ(msg[0].ids.pid, msg[0].tgid_info.tgid);
907 }
908
909 /* A receiver asking for both thread and process pidfd should get a unique
910 * msg for each thread writing
911 */
TEST(scm_pidfd_thread_stream_splits_on_threads)912 TEST(scm_pidfd_thread_stream_splits_on_threads)
913 {
914 struct pidfd_msg msg[2] = { 0 };
915 int i;
916
917 ASSERT_EQ(0, pidfd_flow(send_ids_thread, 2, true, true, msg, 2));
918
919 for (i = 0; i < 2; i++) {
920 EXPECT_EQ(sizeof(struct thread_ids), msg[i].len);
921 EXPECT_TRUE(msg[i].have_tgid);
922 EXPECT_TRUE(msg[i].have_thread);
923
924 /* Make sure the info makes sense for the pidfd type */
925 EXPECT_EQ(msg[i].ids.pid, msg[i].tgid_info.pid);
926 EXPECT_EQ(msg[i].ids.pid, msg[i].tgid_info.tgid);
927 EXPECT_EQ(msg[i].ids.tid, msg[i].thread_info.pid);
928 EXPECT_EQ(msg[i].ids.pid, msg[i].thread_info.tgid);
929 EXPECT_NE(msg[i].ids.pid, msg[i].ids.tid);
930 }
931
932 /* Make sure we really got unique threads per message */
933 EXPECT_NE(msg[0].ids.tid, msg[1].ids.tid);
934 EXPECT_EQ(msg[0].ids.pid, msg[1].ids.pid);
935 EXPECT_EQ(msg[0].tgid_info.pid, msg[1].tgid_info.pid);
936 EXPECT_NE(msg[0].thread_info.pid, msg[1].thread_info.pid);
937 }
938
939 /* Sends from the thread-group leader */
leader_flow(bool want_thread,struct pidfd_msg * out)940 static int leader_flow(bool want_thread, struct pidfd_msg *out)
941 {
942 struct thread_ids ids = {
943 .pid = getpid(),
944 .tid = gettid(),
945 };
946 int sk[2];
947 int on = 1;
948 int ret;
949
950 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sk))
951 return -1;
952
953 if (setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
954 log_err("Failed to set SO_PASSPIDFD");
955 return -1;
956 }
957
958 if (want_thread &&
959 setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD_THREAD, &on, sizeof(on))) {
960 log_err("Failed to set SO_PASSPIDFD_THREAD");
961 return -1;
962 }
963
964 if (send(sk[1], &ids, sizeof(ids), 0) != sizeof(ids)) {
965 log_err("send");
966 return -1;
967 }
968
969 ret = read_pidfd_msg(sk[0], out);
970
971 close(sk[0]);
972 close(sk[1]);
973
974 return ret;
975 }
976
TEST(scm_pidfd_leader_sender)977 TEST(scm_pidfd_leader_sender)
978 {
979 struct pidfd_msg msg = { 0 };
980
981 ASSERT_EQ(getpid(), gettid());
982
983 ASSERT_EQ(0, leader_flow(false, &msg));
984 ASSERT_TRUE(msg.have_tgid);
985 EXPECT_FALSE(msg.have_thread);
986
987 EXPECT_EQ(getpid(), msg.tgid_info.pid);
988 EXPECT_EQ(getpid(), msg.tgid_info.tgid);
989 EXPECT_FALSE(msg.tgid_flags & O_EXCL);
990 }
991
TEST(scm_pidfd_thread_leader_sender)992 TEST(scm_pidfd_thread_leader_sender)
993 {
994 struct pidfd_msg msg = { 0 };
995
996 ASSERT_EQ(getpid(), gettid());
997
998 ASSERT_EQ(0, leader_flow(true, &msg));
999 ASSERT_TRUE(msg.have_tgid);
1000 ASSERT_TRUE(msg.have_thread);
1001
1002 EXPECT_EQ(getpid(), msg.tgid_info.pid);
1003 EXPECT_EQ(getpid(), msg.tgid_info.tgid);
1004 EXPECT_EQ(getpid(), msg.thread_info.pid);
1005 EXPECT_EQ(getpid(), msg.thread_info.tgid);
1006
1007 EXPECT_FALSE(msg.tgid_flags & O_EXCL);
1008 EXPECT_TRUE(msg.thread_flags & O_EXCL);
1009 }
1010
TEST(scm_pidfd_thread_and_group)1011 TEST(scm_pidfd_thread_and_group)
1012 {
1013 struct pidfd_msg msg = { 0 };
1014
1015 ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, true, true, &msg, 1));
1016 ASSERT_NE(msg.ids.pid, msg.ids.tid);
1017 ASSERT_TRUE(msg.have_tgid);
1018 ASSERT_TRUE(msg.have_thread);
1019
1020 EXPECT_EQ(msg.ids.pid, msg.tgid_info.pid);
1021 EXPECT_EQ(msg.ids.pid, msg.tgid_info.tgid);
1022
1023 EXPECT_EQ(msg.ids.tid, msg.thread_info.pid);
1024 EXPECT_EQ(msg.ids.pid, msg.thread_info.tgid);
1025 }
1026
TEST(scm_pidfd_thread)1027 TEST(scm_pidfd_thread)
1028 {
1029 struct pidfd_msg msg = { 0 };
1030
1031 ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, false, true, &msg, 1));
1032 ASSERT_NE(msg.ids.pid, msg.ids.tid);
1033 ASSERT_TRUE(msg.have_thread);
1034 EXPECT_FALSE(msg.have_tgid);
1035 EXPECT_EQ(msg.ids.tid, msg.thread_info.pid);
1036 EXPECT_EQ(msg.ids.pid, msg.thread_info.tgid);
1037 }
1038
TEST(scm_pidfd_thread_group)1039 TEST(scm_pidfd_thread_group)
1040 {
1041 struct pidfd_msg msg = { 0 };
1042
1043 ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, true, false, &msg, 1));
1044 ASSERT_NE(msg.ids.pid, msg.ids.tid);
1045 ASSERT_TRUE(msg.have_tgid);
1046 EXPECT_FALSE(msg.have_thread);
1047 EXPECT_EQ(msg.ids.pid, msg.tgid_info.pid);
1048 EXPECT_EQ(msg.ids.pid, msg.tgid_info.tgid);
1049 }
1050
TEST(scm_pidfd_thread_creds)1051 TEST(scm_pidfd_thread_creds)
1052 {
1053 struct pidfd_msg msg = { 0 };
1054
1055 ASSERT_EQ(0, pidfd_flow(send_ids_creds_thread, 1, true, true, &msg, 1));
1056 ASSERT_NE(msg.ids.pid, msg.ids.tid);
1057 ASSERT_TRUE(msg.have_tgid);
1058 ASSERT_TRUE(msg.have_thread);
1059 EXPECT_EQ(msg.ids.pid, msg.tgid_info.pid);
1060 EXPECT_EQ(msg.ids.pid, msg.tgid_info.tgid);
1061 EXPECT_EQ(msg.ids.tid, msg.thread_info.pid);
1062 EXPECT_EQ(msg.ids.pid, msg.thread_info.tgid);
1063 }
1064
peer_connect_thread(void * arg)1065 static void *peer_connect_thread(void *arg)
1066 {
1067 struct sock_addr *sa = arg;
1068 struct thread_ids ids = {
1069 .pid = getpid(),
1070 .tid = gettid(),
1071 };
1072 int fd;
1073 char sync;
1074
1075 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1076 if (fd < 0)
1077 return (void *)1;
1078
1079 if (connect(fd, (struct sockaddr *)&sa->listen_addr, sa->addrlen))
1080 return (void *)1;
1081
1082 if (send(fd, &ids, sizeof(ids), 0) != sizeof(ids))
1083 return (void *)1;
1084
1085 /* stay alive until the server has looked at our pidfd */
1086 if (read(fd, &sync, 1) != 1)
1087 return (void *)1;
1088
1089 close(fd);
1090 return NULL;
1091 }
1092
peer_pidfd_info(int fd,int optname,struct pidfd_info * info)1093 static int peer_pidfd_info(int fd, int optname, struct pidfd_info *info)
1094 {
1095 int pidfd;
1096 socklen_t len = sizeof(pidfd);
1097
1098 if (getsockopt(fd, SOL_SOCKET, optname, &pidfd, &len)) {
1099 log_err("getsockopt(SO_PEERPIDFD*)");
1100 return -1;
1101 }
1102
1103 info->mask = PIDFD_INFO_PID;
1104 if (ioctl(pidfd, PIDFD_GET_INFO, info)) {
1105 log_err("ioctl(PIDFD_GET_INFO)");
1106 close(pidfd);
1107 return -1;
1108 }
1109
1110 close(pidfd);
1111 return 0;
1112 }
1113
1114 /* SO_PEERPIDFD_THREAD returns a pidfd for the peer's connecting thread. */
TEST(so_peerpidfd_thread)1115 TEST(so_peerpidfd_thread)
1116 {
1117 struct sock_addr sa;
1118 struct thread_ids ids;
1119 struct pidfd_info info;
1120 pthread_t thread;
1121 void *tret;
1122 int server, cfd;
1123
1124 server = socket(AF_UNIX, SOCK_STREAM, 0);
1125 ASSERT_LE(0, server);
1126
1127 fill_sockaddr(&sa, true);
1128 ASSERT_EQ(0, bind(server, (struct sockaddr *)&sa.listen_addr, sa.addrlen));
1129 ASSERT_EQ(0, listen(server, 1));
1130
1131 ASSERT_EQ(0, pthread_create(&thread, NULL, peer_connect_thread, &sa));
1132
1133 cfd = accept(server, NULL, NULL);
1134 ASSERT_LE(0, cfd);
1135
1136 ASSERT_EQ(sizeof(ids), recv(cfd, &ids, sizeof(ids), MSG_WAITALL));
1137 ASSERT_NE(ids.pid, ids.tid);
1138
1139 /* SO_PEERPIDFD refers to the peer's thread-group. */
1140 ASSERT_EQ(0, peer_pidfd_info(cfd, SO_PEERPIDFD, &info));
1141 EXPECT_EQ(ids.pid, info.pid);
1142 EXPECT_EQ(ids.pid, info.tgid);
1143
1144 /* SO_PEERPIDFD_THREAD refers to the connecting thread. */
1145 ASSERT_EQ(0, peer_pidfd_info(cfd, SO_PEERPIDFD_THREAD, &info));
1146 EXPECT_EQ(ids.tid, info.pid);
1147 EXPECT_EQ(ids.pid, info.tgid);
1148
1149 /* release the connecting thread */
1150 ASSERT_EQ(1, write(cfd, "x", 1));
1151 ASSERT_EQ(0, pthread_join(thread, &tret));
1152 ASSERT_EQ(NULL, tret);
1153
1154 close(cfd);
1155 close(server);
1156 }
1157
1158 TEST_HARNESS_MAIN
1159