1 /*
2 * Check decoding of struct msghdr.msg_name* arguments of recvmsg syscall.
3 *
4 * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2016-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18
19 #undef TEST_RECVMSG_BOGUS_ADDR
20
21 /*
22 * Sadly, musl recvmsg wrapper blindly dereferences the 2nd argument,
23 * so limit these tests to glibc that hopefully doesn't.
24 */
25 #ifndef __GLIBC__
26 # define TEST_RECVMSG_BOGUS_ADDR 0
27 #endif
28
29 /*
30 * Sadly, starting with commit
31 * glibc-2.33.9000-707-g13c51549e2077f2f3bf84e8fd0b46d8b0c615912, on every
32 * 32-bit architecture where 32-bit time_t support is enabled, glibc blindly
33 * dereferences the 2nd argument of recvmsg call.
34 */
35 #if GLIBC_PREREQ_GE(2, 33) && defined __TIMESIZE && __TIMESIZE != 64
36 # define TEST_RECVMSG_BOGUS_ADDR 0
37 #endif
38
39 #ifndef TEST_RECVMSG_BOGUS_ADDR
40 # define TEST_RECVMSG_BOGUS_ADDR 1
41 #endif
42
43 static int
44 send_recv(const int send_fd, const int recv_fd,
45 struct msghdr *const msg, const int flags)
46 {
47 if (send(send_fd, "A", 1, 0) != 1)
48 perror_msg_and_skip("send");
49 return recvmsg(recv_fd, msg, flags);
50 }
51
52 static void
53 test_msg_name(const int send_fd, const int recv_fd)
54 {
55 TAIL_ALLOC_OBJECT_CONST_PTR(char, recv_buf);
56 TAIL_ALLOC_OBJECT_CONST_PTR(struct iovec, iov);
57 iov->iov_base = recv_buf;
58 iov->iov_len = sizeof(*recv_buf);
59
60 TAIL_ALLOC_OBJECT_CONST_PTR(struct sockaddr_un, addr);
61 TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, msg);
62 msg->msg_name = addr;
63 msg->msg_namelen = sizeof(*addr);
64 msg->msg_iov = iov;
65 msg->msg_iovlen = 1;
66 msg->msg_control = 0;
67 msg->msg_controllen = 0;
68 msg->msg_flags = 0;
69
70 int rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
71 if (rc < 0)
72 perror_msg_and_skip("recvmsg");
73 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}"
74 ", msg_namelen=%d => %d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
75 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
76 " = %d\n",
77 recv_fd, addr->sun_path, (int) sizeof(struct sockaddr_un),
78 (int) msg->msg_namelen, rc);
79
80 memset(addr, 0, sizeof(*addr));
81 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
82 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}"
83 ", msg_namelen=%d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
84 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
85 " = %d\n",
86 recv_fd, addr->sun_path, (int) msg->msg_namelen, rc);
87
88 msg->msg_name = 0;
89 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
90 printf("recvmsg(%d, {msg_name=NULL, msg_namelen=%d"
91 ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1"
92 ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n",
93 recv_fd, (int) msg->msg_namelen, rc);
94
95 const size_t offsetof_sun_path = offsetof(struct sockaddr_un, sun_path);
96 msg->msg_name = addr;
97 msg->msg_namelen = offsetof_sun_path;
98 memset(addr->sun_path, 'A', sizeof(addr->sun_path));
99
100 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
101 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX}, msg_namelen=%d => %d"
102 ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1"
103 ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n",
104 recv_fd, (int) offsetof_sun_path, (int) msg->msg_namelen, rc);
105
106 msg->msg_namelen = sizeof(struct sockaddr);
107 msg->msg_name = ((void *) (addr + 1)) - msg->msg_namelen;
108 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
109 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%.*s\"}"
110 ", msg_namelen=%d => %d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
111 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
112 " = %d\n",
113 recv_fd, (int) (sizeof(struct sockaddr) - offsetof_sun_path),
114 ((struct sockaddr_un *) msg->msg_name)->sun_path,
115 (int) sizeof(struct sockaddr), (int) msg->msg_namelen, rc);
116
117 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
118 printf("recvmsg(%d, {msg_namelen=%d}, MSG_DONTWAIT) = %d %s (%m)\n",
119 recv_fd, (int) msg->msg_namelen, rc, errno2name());
120
121 #if TEST_RECVMSG_BOGUS_ADDR
122 /*
123 * When recvmsg is called with a valid descriptor
124 * but inaccessible memory, it causes segfaults on some architectures.
125 * As in these cases we test decoding of failed recvmsg calls,
126 * it's ok to fail recvmsg with any reason as long as
127 * it doesn't read that inaccessible memory.
128 */
129 rc = send_recv(send_fd, -1, msg + 1, 0);
130 printf("recvmsg(-1, %p, 0) = %d %s (%m)\n",
131 msg + 1, rc, errno2name());
132
133 rc = send_recv(send_fd, -1, 0, 0);
134 printf("recvmsg(-1, NULL, 0) = %d %s (%m)\n",
135 rc, errno2name());
136 #endif
137 }
138
139 int
140 main(void)
141 {
142 int fds[2];
143 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
144 perror_msg_and_skip("socketpair");
145
146 const struct sockaddr_un un = {
147 .sun_family = AF_UNIX,
148 .sun_path = "msg_name-recvmsg.test.send.socket"
149 };
150
151 (void) unlink(un.sun_path);
152 if (bind(fds[1], (const void *) &un, sizeof(un)))
153 perror_msg_and_skip("bind");
154 (void) unlink(un.sun_path);
155
156 test_msg_name(fds[1], fds[0]);
157
158 puts("+++ exited with 0 +++");
159 return 0;
160 }