1 /*
2 * Check decoding of SCM_CREDENTIALS control messages.
3 *
4 * Copyright (c) 2023 Dmitry V. Levin <ldv@strace.io>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include <assert.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/socket.h>
16
17 static void
18 print_ucred(const struct cmsghdr *c)
19 {
20 const void *cmsg_header = c;
21 const void *cmsg_data = CMSG_DATA(c);
22 struct ucred uc;
23 const unsigned int expected_len = sizeof(uc);
24 const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header);
25
26 if (expected_len != data_len)
27 perror_msg_and_fail("sizeof(struct ucred) = %u"
28 ", data_len = %u\n",
29 expected_len, data_len);
30
31 memcpy(&uc, cmsg_data, sizeof(uc));
32 printf("{pid=%u, uid=%u, gid=%u}", uc.pid, uc.uid, uc.gid);
33 }
34
35 int
36 main(void)
37 {
38 skip_if_unavailable("/proc/self/fd/");
39
40 int sv[2];
41 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
42 perror_msg_and_skip("socketpair AF_UNIX SOCK_STREAM");
43
44 int one = 1;
45 if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)))
46 perror_msg_and_skip("setsockopt");
47
48 char sym = 'A';
49 if (send(sv[1], &sym, 1, 0) != 1)
50 perror_msg_and_fail("send");
51 if (close(sv[1]))
52 perror_msg_and_fail("close send");
53
54 struct ucred uc;
55 unsigned int cmsg_size = CMSG_SPACE(sizeof(uc));
56 struct cmsghdr *cmsg = tail_alloc(cmsg_size);
57 memset(cmsg, 0, cmsg_size);
58
59 struct iovec iov = {
60 .iov_base = &sym,
61 .iov_len = sizeof(sym)
62 };
63 struct msghdr mh = {
64 .msg_iov = &iov,
65 .msg_iovlen = 1,
66 .msg_control = cmsg,
67 .msg_controllen = cmsg_size
68 };
69
70 if (recvmsg(sv[0], &mh, 0) != 1)
71 perror_msg_and_fail("recvmsg");
72 if (close(sv[0]))
73 perror_msg_and_fail("close recv");
74
75 printf("recvmsg(%d, {msg_name=NULL, msg_namelen=0"
76 ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1",
77 sv[0]);
78
79 bool found = false;
80 if (mh.msg_controllen) {
81 printf(", msg_control=[");
82 for (struct cmsghdr *c = CMSG_FIRSTHDR(&mh); c;
83 c = CMSG_NXTHDR(&mh, c)) {
84 printf("%s{cmsg_len=%lu, cmsg_level=",
85 (c == cmsg ? "" : ", "),
86 (unsigned long) c->cmsg_len);
87 if (c->cmsg_level == SOL_SOCKET) {
88 printf("SOL_SOCKET");
89 } else {
90 printf("%d /* expected SOL_SOCKET == %d */",
91 c->cmsg_level, (int) SOL_SOCKET);
92 }
93 printf(", cmsg_type=");
94 if (c->cmsg_type == SCM_CREDENTIALS) {
95 printf("SCM_CREDENTIALS, cmsg_data=");
96 print_ucred(c);
97 found = true;
98 } else {
99 printf("%d /* expected SCM_CREDENTIALS == %d */",
100 c->cmsg_type, (int) SCM_CREDENTIALS);
101 }
102 printf("}");
103 }
104 printf("]");
105 }
106 printf(", msg_controllen=%lu, msg_flags=0}, 0) = 1\n",
107 (unsigned long) mh.msg_controllen);
108
109 if (!found)
110 error_msg_and_fail("SCM_CREDENTIALS not found");
111
112 puts("+++ exited with 0 +++");
113 return 0;
114 }