1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2019 Bjoern A. Zeeb 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/errno.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <poll.h> 35 36 #include <atf-c.h> 37 38 ATF_TC_WITHOUT_HEAD(socket_afinet); 39 ATF_TC_BODY(socket_afinet, tc) 40 { 41 int sd; 42 43 sd = socket(PF_INET, SOCK_DGRAM, 0); 44 ATF_CHECK(sd >= 0); 45 46 close(sd); 47 } 48 49 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_zero); 50 ATF_TC_BODY(socket_afinet_bind_zero, tc) 51 { 52 int sd, rc; 53 struct sockaddr_in sin; 54 55 if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) 56 atf_tc_skip("doesn't work when mac_portacl(4) loaded (https://bugs.freebsd.org/238781)"); 57 58 sd = socket(PF_INET, SOCK_DGRAM, 0); 59 ATF_CHECK(sd >= 0); 60 61 bzero(&sin, sizeof(sin)); 62 /* 63 * For AF_INET we do not check the family in in_pcbbind_setup(9), 64 * sa_len gets set from the syscall argument in getsockaddr(9), 65 * so we bind to 0:0. 66 */ 67 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 68 ATF_CHECK_EQ(0, rc); 69 70 close(sd); 71 } 72 73 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok); 74 ATF_TC_BODY(socket_afinet_bind_ok, tc) 75 { 76 int sd, rc; 77 struct sockaddr_in sin; 78 79 sd = socket(PF_INET, SOCK_DGRAM, 0); 80 ATF_CHECK(sd >= 0); 81 82 bzero(&sin, sizeof(sin)); 83 sin.sin_family = AF_INET; 84 sin.sin_len = sizeof(sin); 85 sin.sin_port = htons(6666); 86 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 87 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 88 ATF_CHECK_EQ(0, rc); 89 90 close(sd); 91 } 92 93 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup); 94 ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc) 95 { 96 int ss, ss2, cs, rc; 97 struct sockaddr_in sin; 98 struct pollfd pfd; 99 int one = 1; 100 101 /* Verify that we don't expose POLLRDHUP if not requested. */ 102 103 /* Server setup. */ 104 ss = socket(PF_INET, SOCK_STREAM, 0); 105 ATF_CHECK(ss >= 0); 106 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 107 ATF_CHECK_EQ(0, rc); 108 bzero(&sin, sizeof(sin)); 109 sin.sin_family = AF_INET; 110 sin.sin_len = sizeof(sin); 111 sin.sin_port = htons(6666); 112 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 113 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 114 ATF_CHECK_EQ(0, rc); 115 rc = listen(ss, 1); 116 ATF_CHECK_EQ(0, rc); 117 118 /* Client connects, server accepts. */ 119 cs = socket(PF_INET, SOCK_STREAM, 0); 120 ATF_CHECK(cs >= 0); 121 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 122 ATF_CHECK_EQ(0, rc); 123 ss2 = accept(ss, NULL, NULL); 124 ATF_CHECK(ss2 >= 0); 125 126 /* Server can write, sees only POLLOUT. */ 127 pfd.fd = ss2; 128 pfd.events = POLLIN | POLLOUT; 129 rc = poll(&pfd, 1, 0); 130 ATF_CHECK_EQ(1, rc); 131 ATF_CHECK_EQ(POLLOUT, pfd.revents); 132 133 /* Client closes socket! */ 134 rc = close(cs); 135 ATF_CHECK_EQ(0, rc); 136 137 /* 138 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask. 139 * Need non-zero timeout to wait for the FIN to arrive and trigger the 140 * socket to become readable. 141 */ 142 pfd.fd = ss2; 143 pfd.events = POLLIN; 144 rc = poll(&pfd, 1, 60000); 145 ATF_CHECK_EQ(1, rc); 146 ATF_CHECK_EQ(POLLIN, pfd.revents); 147 148 close(ss2); 149 close(ss); 150 } 151 152 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup); 153 ATF_TC_BODY(socket_afinet_poll_rdhup, tc) 154 { 155 int ss, ss2, cs, rc; 156 struct sockaddr_in sin; 157 struct pollfd pfd; 158 char buffer; 159 int one = 1; 160 161 /* Verify that server sees POLLRDHUP if it asks for it. */ 162 163 /* Server setup. */ 164 ss = socket(PF_INET, SOCK_STREAM, 0); 165 ATF_CHECK(ss >= 0); 166 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 167 ATF_CHECK_EQ(0, rc); 168 bzero(&sin, sizeof(sin)); 169 sin.sin_family = AF_INET; 170 sin.sin_len = sizeof(sin); 171 sin.sin_port = htons(6666); 172 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 173 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 174 ATF_CHECK_EQ(0, rc); 175 rc = listen(ss, 1); 176 ATF_CHECK_EQ(0, rc); 177 178 /* Client connects, server accepts. */ 179 cs = socket(PF_INET, SOCK_STREAM, 0); 180 ATF_CHECK(cs >= 0); 181 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 182 ATF_CHECK_EQ(0, rc); 183 ss2 = accept(ss, NULL, NULL); 184 ATF_CHECK(ss2 >= 0); 185 186 /* Server can write, so sees POLLOUT. */ 187 pfd.fd = ss2; 188 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 189 rc = poll(&pfd, 1, 0); 190 ATF_CHECK_EQ(1, rc); 191 ATF_CHECK_EQ(POLLOUT, pfd.revents); 192 193 /* Client writes two bytes, server reads only one of them. */ 194 rc = write(cs, "xx", 2); 195 ATF_CHECK_EQ(2, rc); 196 rc = read(ss2, &buffer, 1); 197 ATF_CHECK_EQ(1, rc); 198 199 /* Server can read, so sees POLLIN. */ 200 pfd.fd = ss2; 201 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 202 rc = poll(&pfd, 1, 0); 203 ATF_CHECK_EQ(1, rc); 204 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents); 205 206 /* Client closes socket! */ 207 rc = close(cs); 208 ATF_CHECK_EQ(0, rc); 209 210 /* 211 * Server sees Linux-style POLLRDHUP. Note that this is the case even 212 * though one byte of data remains unread. 213 * 214 * This races against the delivery of FIN caused by the close() above. 215 * Sometimes (more likely when run under truss or if another system 216 * call is added in between) it hits the path where sopoll_generic() 217 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag 218 * SB_SEL so that it's woken up almost immediately and runs again, 219 * which is why we need a non-zero timeout here. 220 */ 221 pfd.fd = ss2; 222 pfd.events = POLLRDHUP; 223 rc = poll(&pfd, 1, 60000); 224 ATF_CHECK_EQ(1, rc); 225 ATF_CHECK_EQ(POLLRDHUP, pfd.revents); 226 227 close(ss2); 228 close(ss); 229 } 230 231 ATF_TP_ADD_TCS(tp) 232 { 233 234 ATF_TP_ADD_TC(tp, socket_afinet); 235 ATF_TP_ADD_TC(tp, socket_afinet_bind_zero); 236 ATF_TP_ADD_TC(tp, socket_afinet_bind_ok); 237 ATF_TP_ADD_TC(tp, socket_afinet_poll_no_rdhup); 238 ATF_TP_ADD_TC(tp, socket_afinet_poll_rdhup); 239 240 return atf_no_error(); 241 } 242