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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "tests.h" 32 #include <stddef.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <sys/socket.h> 37 #include <sys/un.h> 38 39 static int 40 send_recv(const int send_fd, const int recv_fd, 41 struct msghdr *const msg, const int flags) 42 { 43 if (send(send_fd, "A", 1, 0) != 1) 44 perror_msg_and_skip("send"); 45 return recvmsg(recv_fd, msg, flags); 46 } 47 48 static void 49 test_msg_name(const int send_fd, const int recv_fd) 50 { 51 TAIL_ALLOC_OBJECT_CONST_PTR(char, recv_buf); 52 TAIL_ALLOC_OBJECT_CONST_PTR(struct iovec, iov); 53 iov->iov_base = recv_buf; 54 iov->iov_len = sizeof(*recv_buf); 55 56 TAIL_ALLOC_OBJECT_CONST_PTR(struct sockaddr_un, addr); 57 TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, msg); 58 msg->msg_name = addr; 59 msg->msg_namelen = sizeof(*addr); 60 msg->msg_iov = iov; 61 msg->msg_iovlen = 1; 62 msg->msg_control = 0; 63 msg->msg_controllen = 0; 64 msg->msg_flags = 0; 65 66 int rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT); 67 if (rc < 0) 68 perror_msg_and_skip("recvmsg"); 69 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}" 70 ", msg_namelen=%d->%d, msg_iov=[{iov_base=\"A\", iov_len=1}]" 71 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)" 72 " = %d\n", 73 recv_fd, addr->sun_path, (int) sizeof(struct sockaddr_un), 74 (int) msg->msg_namelen, rc); 75 76 memset(addr, 0, sizeof(*addr)); 77 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT); 78 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}" 79 ", msg_namelen=%d, msg_iov=[{iov_base=\"A\", iov_len=1}]" 80 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)" 81 " = %d\n", 82 recv_fd, addr->sun_path, (int) msg->msg_namelen, rc); 83 84 msg->msg_name = 0; 85 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT); 86 printf("recvmsg(%d, {msg_name=NULL, msg_namelen=%d" 87 ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1" 88 ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n", 89 recv_fd, (int) msg->msg_namelen, rc); 90 91 const size_t offsetof_sun_path = offsetof(struct sockaddr_un, sun_path); 92 msg->msg_name = addr; 93 msg->msg_namelen = offsetof_sun_path; 94 memset(addr->sun_path, 'A', sizeof(addr->sun_path)); 95 96 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT); 97 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX}, msg_namelen=%d->%d" 98 ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1" 99 ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n", 100 recv_fd, (int) offsetof_sun_path, (int) msg->msg_namelen, rc); 101 102 msg->msg_namelen = sizeof(struct sockaddr); 103 msg->msg_name = ((void *) (addr + 1)) - msg->msg_namelen; 104 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT); 105 printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%.*s\"}" 106 ", msg_namelen=%d->%d, msg_iov=[{iov_base=\"A\", iov_len=1}]" 107 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)" 108 " = %d\n", 109 recv_fd, (int) (sizeof(struct sockaddr) - offsetof_sun_path), 110 ((struct sockaddr_un *) msg->msg_name)->sun_path, 111 (int) sizeof(struct sockaddr), (int) msg->msg_namelen, rc); 112 113 rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT); 114 printf("recvmsg(%d, {msg_namelen=%d}, MSG_DONTWAIT) = %d %s (%m)\n", 115 recv_fd, (int) msg->msg_namelen, rc, errno2name()); 116 117 /* 118 * When recvmsg is called with a valid descriptor 119 * but inaccessible memory, it causes segfaults on some architectures. 120 * As in these cases we test decoding of failed recvmsg calls, 121 * it's ok to fail recvmsg with any reason as long as 122 * it doesn't read that inaccessible memory. 123 */ 124 125 /* 126 * Sadly, musl recvmsg wrapper blindly dereferences 2nd argument, 127 * so limit this test to glibc that doesn't. 128 */ 129 #ifdef __GLIBC__ 130 rc = send_recv(send_fd, -1, msg + 1, 0); 131 printf("recvmsg(-1, %p, 0) = %d %s (%m)\n", 132 msg + 1, rc, errno2name()); 133 #endif 134 135 rc = send_recv(send_fd, -1, 0, 0); 136 printf("recvmsg(-1, NULL, 0) = %d %s (%m)\n", 137 rc, errno2name()); 138 } 139 140 int 141 main(void) 142 { 143 int fds[2]; 144 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) 145 perror_msg_and_skip("socketpair"); 146 147 const struct sockaddr_un un = { 148 .sun_family = AF_UNIX, 149 .sun_path = "msg_name-recvmsg.test.send.socket" 150 }; 151 152 (void) unlink(un.sun_path); 153 if (bind(fds[1], (const void *) &un, sizeof(un))) 154 perror_msg_and_skip("bind"); 155 (void) unlink(un.sun_path); 156 157 test_msg_name(fds[1], fds[0]); 158 159 puts("+++ exited with 0 +++"); 160 return 0; 161 } 162