]> granicus.if.org Git - strace/blob - tests/msg_name.c
5b73025c60d611d516bc8721ec34b57ca77fa09d
[strace] / tests / msg_name.c
1 /*
2  * Check decoding of struct msghdr.msg_name* arguments of recvmsg syscall.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016-2017 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 static int
20 send_recv(const int send_fd, const int recv_fd,
21          struct msghdr *const msg, const int flags)
22 {
23         if (send(send_fd, "A", 1, 0) != 1)
24                 perror_msg_and_skip("send");
25         return recvmsg(recv_fd, msg, flags);
26 }
27
28 static void
29 test_msg_name(const int send_fd, const int recv_fd)
30 {
31         TAIL_ALLOC_OBJECT_CONST_PTR(char, recv_buf);
32         TAIL_ALLOC_OBJECT_CONST_PTR(struct iovec, iov);
33         iov->iov_base = recv_buf;
34         iov->iov_len = sizeof(*recv_buf);
35
36         TAIL_ALLOC_OBJECT_CONST_PTR(struct sockaddr_un, addr);
37         TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, msg);
38         msg->msg_name = addr;
39         msg->msg_namelen = sizeof(*addr);
40         msg->msg_iov = iov;
41         msg->msg_iovlen = 1;
42         msg->msg_control = 0;
43         msg->msg_controllen = 0;
44         msg->msg_flags = 0;
45
46         int rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
47         if (rc < 0)
48                 perror_msg_and_skip("recvmsg");
49         printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}"
50                ", msg_namelen=%d->%d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
51                ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
52                " = %d\n",
53                recv_fd, addr->sun_path, (int) sizeof(struct sockaddr_un),
54                (int) msg->msg_namelen, rc);
55
56         memset(addr, 0, sizeof(*addr));
57         rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
58         printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}"
59                ", msg_namelen=%d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
60                ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
61                " = %d\n",
62                recv_fd, addr->sun_path, (int) msg->msg_namelen, rc);
63
64         msg->msg_name = 0;
65         rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
66         printf("recvmsg(%d, {msg_name=NULL, msg_namelen=%d"
67                ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1"
68                ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n",
69                recv_fd, (int) msg->msg_namelen, rc);
70
71         const size_t offsetof_sun_path = offsetof(struct sockaddr_un, sun_path);
72         msg->msg_name = addr;
73         msg->msg_namelen = offsetof_sun_path;
74         memset(addr->sun_path, 'A', sizeof(addr->sun_path));
75
76         rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
77         printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX}, msg_namelen=%d->%d"
78                ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1"
79                ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n",
80                recv_fd, (int) offsetof_sun_path, (int) msg->msg_namelen, rc);
81
82         msg->msg_namelen = sizeof(struct sockaddr);
83         msg->msg_name = ((void *) (addr + 1)) - msg->msg_namelen;
84         rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
85         printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%.*s\"}"
86                ", msg_namelen=%d->%d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
87                ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
88                " = %d\n",
89                recv_fd, (int) (sizeof(struct sockaddr) - offsetof_sun_path),
90                ((struct sockaddr_un *) msg->msg_name)->sun_path,
91                (int) sizeof(struct sockaddr), (int) msg->msg_namelen, rc);
92
93         rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
94         printf("recvmsg(%d, {msg_namelen=%d}, MSG_DONTWAIT) = %d %s (%m)\n",
95                recv_fd, (int) msg->msg_namelen, rc, errno2name());
96
97         /*
98          * When recvmsg is called with a valid descriptor
99          * but inaccessible memory, it causes segfaults on some architectures.
100          * As in these cases we test decoding of failed recvmsg calls,
101          * it's ok to fail recvmsg with any reason as long as
102          * it doesn't read that inaccessible memory.
103          */
104
105         /*
106          * Sadly, musl recvmsg wrapper blindly dereferences 2nd argument,
107          * so limit this test to glibc that doesn't.
108          */
109 #ifdef __GLIBC__
110         rc = send_recv(send_fd, -1, msg + 1, 0);
111         printf("recvmsg(-1, %p, 0) = %d %s (%m)\n",
112                msg + 1, rc, errno2name());
113 #endif
114
115         rc = send_recv(send_fd, -1, 0, 0);
116         printf("recvmsg(-1, NULL, 0) = %d %s (%m)\n",
117                rc, errno2name());
118 }
119
120 int
121 main(void)
122 {
123         int fds[2];
124         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
125                 perror_msg_and_skip("socketpair");
126
127         const struct sockaddr_un un = {
128                 .sun_family = AF_UNIX,
129                 .sun_path = "msg_name-recvmsg.test.send.socket"
130         };
131
132         (void) unlink(un.sun_path);
133         if (bind(fds[1], (const void *) &un, sizeof(un)))
134                 perror_msg_and_skip("bind");
135         (void) unlink(un.sun_path);
136
137         test_msg_name(fds[1], fds[0]);
138
139         puts("+++ exited with 0 +++");
140         return 0;
141 }