unix_passfd_test.c (292814) | unix_passfd_test.c (292914) |
---|---|
1/*- 2 * Copyright (c) 2005 Robert N. M. Watson 3 * Copyright (c) 2015 Mark Johnston 4 * All rights reserved. 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: --- 10 unchanged lines hidden (view full) --- 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 * | 1/*- 2 * Copyright (c) 2005 Robert N. M. Watson 3 * Copyright (c) 2015 Mark Johnston 4 * All rights reserved. 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: --- 10 unchanged lines hidden (view full) --- 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 * $FreeBSD: head/tools/regression/sockets/unix_passfd/unix_passfd.c 292814 2015-12-28 00:53:37Z ngie $ | 27 * $FreeBSD: head/tests/sys/kern/unix_passfd_test.c 292914 2015-12-30 11:15:07Z ngie $ |
28 */ 29 30#include <sys/types.h> 31#include <sys/socket.h> 32#include <sys/stat.h> 33#include <sys/sysctl.h> 34#include <sys/un.h> 35 | 28 */ 29 30#include <sys/types.h> 31#include <sys/socket.h> 32#include <sys/stat.h> 33#include <sys/sysctl.h> 34#include <sys/un.h> 35 |
36#include | 36#include <errno.h> |
37#include <fcntl.h> 38#include <limits.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 | 37#include <fcntl.h> 38#include <limits.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 |
44#include <atf-c.h> 45 |
|
44/* 45 * UNIX domain sockets allow file descriptors to be passed via "ancillary 46 * data", or control messages. This regression test is intended to exercise 47 * this facility, both performing some basic tests that it operates, and also 48 * causing some kernel edge cases to execute, such as garbage collection when 49 * there are cyclic file descriptor references. Right now we test only with 50 * stream sockets, but ideally we'd also test with datagram sockets. 51 */ 52 53static void | 46/* 47 * UNIX domain sockets allow file descriptors to be passed via "ancillary 48 * data", or control messages. This regression test is intended to exercise 49 * this facility, both performing some basic tests that it operates, and also 50 * causing some kernel edge cases to execute, such as garbage collection when 51 * there are cyclic file descriptor references. Right now we test only with 52 * stream sockets, but ideally we'd also test with datagram sockets. 53 */ 54 55static void |
54domainsocketpair(const char *test, int *fdp) | 56domainsocketpair(int *fdp) |
55{ 56 | 57{ 58 |
57 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) < 0) 58 err(-1, "%s: socketpair(PF_UNIX, SOCK_STREAM)", test); | 59 ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) != -1, 60 "socketpair(PF_UNIX, SOCK_STREAM) failed: %s", strerror(errno)); |
59} 60 61static void 62closesocketpair(int *fdp) 63{ 64 65 close(fdp[0]); 66 close(fdp[1]); 67} 68 69static void | 61} 62 63static void 64closesocketpair(int *fdp) 65{ 66 67 close(fdp[0]); 68 close(fdp[1]); 69} 70 71static void |
70devnull(const char *test, int *fdp) | 72devnull(int *fdp) |
71{ 72 int fd; 73 74 fd = open("/dev/null", O_RDONLY); | 73{ 74 int fd; 75 76 fd = open("/dev/null", O_RDONLY); |
75 if (fd < 0) 76 err(-1, "%s: open(/dev/null)", test); | 77 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); |
77 *fdp = fd; 78} 79 80static void | 78 *fdp = fd; 79} 80 81static void |
81tempfile(const char *test, int *fdp) | 82tempfile(int *fdp) |
82{ 83 char path[PATH_MAX]; 84 int fd; 85 | 83{ 84 char path[PATH_MAX]; 85 int fd; 86 |
86 snprintf(path, PATH_MAX, "/tmp/unix_passfd.XXXXXXXXXXXXXXX"); | 87 snprintf(path, PATH_MAX, "%s/unix_passfd.XXXXXXXXXXXXXXX", 88 getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR")); |
87 fd = mkstemp(path); | 89 fd = mkstemp(path); |
88 if (fd < 0) 89 err(-1, "%s: mkstemp(%s)", test, path); | 90 ATF_REQUIRE_MSG(fd != -1, "mkstemp(%s) failed", path); |
90 (void)unlink(path); 91 *fdp = fd; 92} 93 94static void | 91 (void)unlink(path); 92 *fdp = fd; 93} 94 95static void |
95dofstat(const char *test, int fd, struct stat *sb) | 96dofstat(int fd, struct stat *sb) |
96{ 97 | 97{ 98 |
98 if (fstat(fd, sb) < 0) 99 err(-1, "%s: fstat", test); | 99 ATF_REQUIRE_MSG(fstat(fd, sb) == 0, 100 "fstat failed: %s", strerror(errno)); |
100} 101 102static void | 101} 102 103static void |
103samefile(const char *test, struct stat *sb1, struct stat *sb2) | 104samefile(struct stat *sb1, struct stat *sb2) |
104{ 105 | 105{ 106 |
106 if (sb1->st_dev != sb2->st_dev) 107 errx(-1, "%s: samefile: different device", test); 108 if (sb1->st_ino != sb2->st_ino) 109 errx(-1, "%s: samefile: different inode", test); | 107 ATF_REQUIRE_MSG(sb1->st_dev == sb2->st_dev, "different device"); 108 ATF_REQUIRE_MSG(sb1->st_ino == sb2->st_ino, "different inode"); |
110} 111 112static void | 109} 110 111static void |
113sendfd_payload(const char *test, int sockfd, int sendfd, 114 void *payload, size_t paylen) | 112sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen) |
115{ 116 struct iovec iovec; 117 char message[CMSG_SPACE(sizeof(int))]; 118 struct cmsghdr *cmsghdr; 119 struct msghdr msghdr; 120 ssize_t len; 121 122 bzero(&msghdr, sizeof(msghdr)); 123 bzero(&message, sizeof(message)); 124 125 msghdr.msg_control = message; 126 msghdr.msg_controllen = sizeof(message); 127 128 iovec.iov_base = payload; 129 iovec.iov_len = paylen; 130 131 msghdr.msg_iov = &iovec; 132 msghdr.msg_iovlen = 1; 133 | 113{ 114 struct iovec iovec; 115 char message[CMSG_SPACE(sizeof(int))]; 116 struct cmsghdr *cmsghdr; 117 struct msghdr msghdr; 118 ssize_t len; 119 120 bzero(&msghdr, sizeof(msghdr)); 121 bzero(&message, sizeof(message)); 122 123 msghdr.msg_control = message; 124 msghdr.msg_controllen = sizeof(message); 125 126 iovec.iov_base = payload; 127 iovec.iov_len = paylen; 128 129 msghdr.msg_iov = &iovec; 130 msghdr.msg_iovlen = 1; 131 |
134 cmsghdr = (struct cmsghdr *)message; | 132 cmsghdr = (struct cmsghdr *)(void*)message; |
135 cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); 136 cmsghdr->cmsg_level = SOL_SOCKET; 137 cmsghdr->cmsg_type = SCM_RIGHTS; | 133 cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); 134 cmsghdr->cmsg_level = SOL_SOCKET; 135 cmsghdr->cmsg_type = SCM_RIGHTS; |
138 *(int *)CMSG_DATA(cmsghdr) = sendfd; | 136 memcpy(CMSG_DATA(cmsghdr), &sendfd, sizeof(int)); |
139 140 len = sendmsg(sockfd, &msghdr, 0); | 137 138 len = sendmsg(sockfd, &msghdr, 0); |
141 if (len < 0) 142 err(-1, "%s: sendmsg", test); 143 if ((size_t)len != paylen) 144 errx(-1, "%s: sendmsg: %zd bytes sent", test, len); | 139 ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno)); 140 ATF_REQUIRE_MSG((size_t)len == paylen, 141 "sendmsg: %zd messages sent; expected: %zu; %s", len, paylen, 142 strerror(errno)); |
145} 146 147static void | 143} 144 145static void |
148sendfd(const char *test, int sockfd, int sendfd) | 146sendfd(int sockfd, int sendfd) |
149{ 150 char ch = 0; 151 | 147{ 148 char ch = 0; 149 |
152 return (sendfd_payload(test, sockfd, sendfd, &ch, sizeof(ch))); | 150 return (sendfd_payload(sockfd, sendfd, &ch, sizeof(ch))); |
153} 154 155static void | 151} 152 153static void |
156recvfd_payload(const char *test, int sockfd, int *recvfd, 157 void *buf, size_t buflen) | 154recvfd_payload(int sockfd, int *recvfd, void *buf, size_t buflen) |
158{ 159 struct cmsghdr *cmsghdr; 160 char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)]; 161 struct msghdr msghdr; 162 struct iovec iovec; 163 ssize_t len; 164 165 bzero(&msghdr, sizeof(msghdr)); 166 167 msghdr.msg_control = message; 168 msghdr.msg_controllen = sizeof(message); 169 170 iovec.iov_base = buf; 171 iovec.iov_len = buflen; 172 173 msghdr.msg_iov = &iovec; 174 msghdr.msg_iovlen = 1; 175 176 len = recvmsg(sockfd, &msghdr, 0); | 155{ 156 struct cmsghdr *cmsghdr; 157 char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)]; 158 struct msghdr msghdr; 159 struct iovec iovec; 160 ssize_t len; 161 162 bzero(&msghdr, sizeof(msghdr)); 163 164 msghdr.msg_control = message; 165 msghdr.msg_controllen = sizeof(message); 166 167 iovec.iov_base = buf; 168 iovec.iov_len = buflen; 169 170 msghdr.msg_iov = &iovec; 171 msghdr.msg_iovlen = 1; 172 173 len = recvmsg(sockfd, &msghdr, 0); |
177 if (len < 0) 178 err(-1, "%s: recvmsg", test); 179 if ((size_t)len != buflen) 180 errx(-1, "%s: recvmsg: %zd bytes received", test, len); | 174 ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno)); 175 ATF_REQUIRE_MSG((size_t)len == buflen, 176 "recvmsg: %zd bytes received; expected %zd", len, buflen); |
181 182 cmsghdr = CMSG_FIRSTHDR(&msghdr); | 177 178 cmsghdr = CMSG_FIRSTHDR(&msghdr); |
183 if (cmsghdr == NULL) 184 errx(-1, "%s: recvmsg: did not receive control message", test); | 179 ATF_REQUIRE_MSG(cmsghdr != NULL, 180 "recvmsg: did not receive control message"); |
185 *recvfd = -1; 186 for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { 187 if (cmsghdr->cmsg_level == SOL_SOCKET && 188 cmsghdr->cmsg_type == SCM_RIGHTS && 189 cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { | 181 *recvfd = -1; 182 for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { 183 if (cmsghdr->cmsg_level == SOL_SOCKET && 184 cmsghdr->cmsg_type == SCM_RIGHTS && 185 cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { |
190 *recvfd = *(int *)CMSG_DATA(cmsghdr); 191 if (*recvfd == -1) 192 errx(-1, "%s: recvmsg: received fd -1", test); | 186 memcpy(recvfd, CMSG_DATA(cmsghdr), sizeof(int)); 187 ATF_REQUIRE(*recvfd != -1); |
193 } 194 } | 188 } 189 } |
195 if (*recvfd == -1) 196 errx(-1, "%s: recvmsg: did not receive single-fd message", 197 test); | 190 ATF_REQUIRE_MSG(*recvfd != -1, 191 "recvmsg: did not receive single-fd message"); |
198} 199 200static void | 192} 193 194static void |
201recvfd(const char *test, int sockfd, int *recvfd) | 195recvfd(int sockfd, int *recvfd) |
202{ 203 char ch = 0; 204 | 196{ 197 char ch = 0; 198 |
205 return (recvfd_payload(test, sockfd, recvfd, &ch, sizeof(ch))); | 199 return (recvfd_payload(sockfd, recvfd, &ch, sizeof(ch))); |
206} 207 | 200} 201 |
208int 209main(void) | 202/* 203 * Put a temporary file into a UNIX domain socket, then take it out and make 204 * sure it's the same file. First time around, don't close the reference 205 * after sending. 206 */ 207ATF_TC_WITHOUT_HEAD(simple_send_fd); 208ATF_TC_BODY(simple_send_fd, tc) |
210{ | 209{ |
211 struct stat putfd_1_stat, putfd_2_stat, getfd_1_stat, getfd_2_stat; 212 int fd[2], putfd_1, putfd_2, getfd_1, getfd_2; 213 const char *test; | 210 struct stat getfd_stat, putfd_stat; 211 int fd[2], getfd, putfd; |
214 | 212 |
215 /* 216 * First test: put a temporary file into a UNIX domain socket, then 217 * take it out and make sure it's the same file. First time around, 218 * don't close the reference after sending. 219 */ 220 test = "test1-simplesendfd"; 221 printf("beginning %s\n", test); 222 223 domainsocketpair(test, fd); 224 tempfile(test, &putfd_1); 225 dofstat(test, putfd_1, &putfd_1_stat); 226 sendfd(test, fd[0], putfd_1); 227 recvfd(test, fd[1], &getfd_1); 228 dofstat(test, getfd_1, &getfd_1_stat); 229 samefile(test, &putfd_1_stat, &getfd_1_stat); 230 close(putfd_1); 231 close(getfd_1); | 213 domainsocketpair(fd); 214 tempfile(&putfd); 215 dofstat(putfd, &putfd_stat); 216 sendfd(fd[0], putfd); 217 recvfd(fd[1], &getfd); 218 dofstat(getfd, &getfd_stat); 219 samefile(&putfd_stat, &getfd_stat); 220 close(putfd); 221 close(getfd); |
232 closesocketpair(fd); | 222 closesocketpair(fd); |
223} |
|
233 | 224 |
234 printf("%s passed\n", test); | 225/* 226 * Same as simple_send_fd, only close the file reference after sending, so that 227 * the only reference is the descriptor in the UNIX domain socket buffer. 228 */ 229ATF_TC_WITHOUT_HEAD(send_and_close); 230ATF_TC_BODY(send_and_close, tc) 231{ 232 struct stat getfd_stat, putfd_stat; 233 int fd[2], getfd, putfd; |
235 | 234 |
236 /* 237 * Second test: same as first, only close the file reference after 238 * sending, so that the only reference is the descriptor in the UNIX 239 * domain socket buffer. 240 */ 241 test = "test2-sendandclose"; 242 printf("beginning %s\n", test); 243 244 domainsocketpair(test, fd); 245 tempfile(test, &putfd_1); 246 dofstat(test, putfd_1, &putfd_1_stat); 247 sendfd(test, fd[0], putfd_1); 248 close(putfd_1); 249 recvfd(test, fd[1], &getfd_1); 250 dofstat(test, getfd_1, &getfd_1_stat); 251 samefile(test, &putfd_1_stat, &getfd_1_stat); 252 close(getfd_1); | 235 domainsocketpair(fd); 236 tempfile(&putfd); 237 dofstat(putfd, &putfd_stat); 238 sendfd(fd[0], putfd); 239 close(putfd); 240 recvfd(fd[1], &getfd); 241 dofstat(getfd, &getfd_stat); 242 samefile(&putfd_stat, &getfd_stat); 243 close(getfd); |
253 closesocketpair(fd); | 244 closesocketpair(fd); |
245} |
|
254 | 246 |
255 printf("%s passed\n", test); | 247/* 248 * Put a temporary file into a UNIX domain socket, then close both endpoints 249 * causing garbage collection to kick off. 250 */ 251ATF_TC_WITHOUT_HEAD(send_and_cancel); 252ATF_TC_BODY(send_and_cancel, tc) 253{ 254 int fd[2], putfd; |
256 | 255 |
257 /* 258 * Third test: put a temporary file into a UNIX domain socket, then 259 * close both endpoints causing garbage collection to kick off. 260 */ 261 test = "test3-sendandcancel"; 262 printf("beginning %s\n", test); 263 264 domainsocketpair(test, fd); 265 tempfile(test, &putfd_1); 266 sendfd(test, fd[0], putfd_1); 267 close(putfd_1); | 256 domainsocketpair(fd); 257 tempfile(&putfd); 258 sendfd(fd[0], putfd); 259 close(putfd); |
268 closesocketpair(fd); | 260 closesocketpair(fd); |
261} |
|
269 | 262 |
270 printf("%s passed\n", test); | 263/* 264 * Send two files. Then receive them. Make sure they are returned in the 265 * right order, and both get there. 266 */ 267ATF_TC_WITHOUT_HEAD(two_files); 268ATF_TC_BODY(two_files, tc) 269{ 270 struct stat getfd_1_stat, getfd_2_stat, putfd_1_stat, putfd_2_stat; 271 int fd[2], getfd_1, getfd_2, putfd_1, putfd_2; |
271 | 272 |
272 /* 273 * Send two files. Then receive them. Make sure they are returned 274 * in the right order, and both get there. 275 */ 276 277 test = "test4-twofile"; 278 printf("beginning %s\n", test); 279 280 domainsocketpair(test, fd); 281 tempfile(test, &putfd_1); 282 tempfile(test, &putfd_2); 283 dofstat(test, putfd_1, &putfd_1_stat); 284 dofstat(test, putfd_2, &putfd_2_stat); 285 sendfd(test, fd[0], putfd_1); 286 sendfd(test, fd[0], putfd_2); | 273 domainsocketpair(fd); 274 tempfile(&putfd_1); 275 tempfile(&putfd_2); 276 dofstat(putfd_1, &putfd_1_stat); 277 dofstat(putfd_2, &putfd_2_stat); 278 sendfd(fd[0], putfd_1); 279 sendfd(fd[0], putfd_2); |
287 close(putfd_1); 288 close(putfd_2); | 280 close(putfd_1); 281 close(putfd_2); |
289 recvfd(test, fd[1], &getfd_1); 290 recvfd(test, fd[1], &getfd_2); 291 dofstat(test, getfd_1, &getfd_1_stat); 292 dofstat(test, getfd_2, &getfd_2_stat); 293 samefile(test, &putfd_1_stat, &getfd_1_stat); 294 samefile(test, &putfd_2_stat, &getfd_2_stat); | 282 recvfd(fd[1], &getfd_1); 283 recvfd(fd[1], &getfd_2); 284 dofstat(getfd_1, &getfd_1_stat); 285 dofstat(getfd_2, &getfd_2_stat); 286 samefile(&putfd_1_stat, &getfd_1_stat); 287 samefile(&putfd_2_stat, &getfd_2_stat); |
295 close(getfd_1); 296 close(getfd_2); 297 closesocketpair(fd); | 288 close(getfd_1); 289 close(getfd_2); 290 closesocketpair(fd); |
291} |
|
298 | 292 |
299 printf("%s passed\n", test); | 293/* 294 * Big bundling test. Send an endpoint of the UNIX domain socket over itself, 295 * closing the door behind it. 296 */ 297ATF_TC_WITHOUT_HEAD(bundle); 298ATF_TC_BODY(bundle, tc) 299{ 300 int fd[2], getfd; |
300 | 301 |
301 /* 302 * Big bundling test. Send an endpoint of the UNIX domain socket 303 * over itself, closing the door behind it. 304 */ | 302 domainsocketpair(fd); |
305 | 303 |
306 test = "test5-bundle"; 307 printf("beginning %s\n", test); 308 309 domainsocketpair(test, fd); 310 311 sendfd(test, fd[0], fd[0]); | 304 sendfd(fd[0], fd[0]); |
312 close(fd[0]); | 305 close(fd[0]); |
313 recvfd(test, fd[1], &getfd_1); 314 close(getfd_1); | 306 recvfd(fd[1], &getfd); 307 close(getfd); |
315 close(fd[1]); | 308 close(fd[1]); |
309} |
|
316 | 310 |
317 printf("%s passed\n", test); | 311/* 312 * Big bundling test part two: Send an endpoint of the UNIX domain socket over 313 * itself, close the door behind it, and never remove it from the other end. 314 */ 315ATF_TC_WITHOUT_HEAD(bundle_cancel); 316ATF_TC_BODY(bundle_cancel, tc) 317{ 318 int fd[2]; |
318 | 319 |
319 /* 320 * Big bundling test part two: Send an endpoint of the UNIX domain 321 * socket over itself, close the door behind it, and never remove it 322 * from the other end. 323 */ 324 325 test = "test6-bundlecancel"; 326 printf("beginning %s\n", test); 327 328 domainsocketpair(test, fd); 329 sendfd(test, fd[0], fd[0]); 330 sendfd(test, fd[1], fd[0]); | 320 domainsocketpair(fd); 321 sendfd(fd[0], fd[0]); 322 sendfd(fd[1], fd[0]); |
331 closesocketpair(fd); | 323 closesocketpair(fd); |
324} |
|
332 | 325 |
333 printf("%s passed\n", test); | 326/* 327 * Test for PR 151758: Send an character device over the UNIX domain socket 328 * and then close both sockets to orphan the device. 329 */ 330ATF_TC_WITHOUT_HEAD(devfs_orphan); 331ATF_TC_BODY(devfs_orphan, tc) 332{ 333 int fd[2], putfd; |
334 | 334 |
335 /* 336 * Test for PR 151758: Send an character device over the UNIX 337 * domain socket and then close both sockets to orphan the 338 * device. 339 */ 340 341 test = "test7-devfsorphan"; 342 printf("beginning %s\n", test); 343 344 domainsocketpair(test, fd); 345 devnull(test, &putfd_1); 346 sendfd(test, fd[0], putfd_1); 347 close(putfd_1); | 335 domainsocketpair(fd); 336 devnull(&putfd); 337 sendfd(fd[0], putfd); 338 close(putfd); |
348 closesocketpair(fd); | 339 closesocketpair(fd); |
340} |
|
349 | 341 |
350 printf("%s passed\n", test); | 342#define LOCAL_SENDSPACE_SYSCTL "net.local.stream.sendspace" |
351 | 343 |
352 /* 353 * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel 354 * prepends a control message to the data. Sender sends large 355 * payload. Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer 356 * limit, and receiver receives truncated data. 357 */ 358 test = "test8-rights+creds+payload"; 359 printf("beginning %s\n", test); | 344/* 345 * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel prepends a 346 * control message to the data. Sender sends large payload. 347 * Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer limit, and receiver 348 * receives truncated data. 349 */ 350ATF_TC_WITHOUT_HEAD(rights_creds_payload); 351ATF_TC_BODY(rights_creds_payload, tc) 352{ 353 const int on = 1; 354 u_long sendspace; 355 size_t len; 356 void *buf; 357 int fd[2], getfd, putfd, rc; |
360 | 358 |
361 { 362 const int on = 1; 363 u_long sendspace; 364 size_t len; 365 void *buf; | 359 atf_tc_expect_fail("PR 181741: Packet loss when 'control' messages " 360 "are present with large data"); |
366 | 361 |
367 len = sizeof(sendspace); 368 if (sysctlbyname("net.local.stream.sendspace", &sendspace, 369 &len, NULL, 0) < 0) 370 err(-1, "%s: sysctlbyname(net.local.stream.sendspace)", 371 test); | 362 len = sizeof(sendspace); 363 rc = sysctlbyname(LOCAL_SENDSPACE_SYSCTL, &sendspace, 364 &len, NULL, 0); 365 ATF_REQUIRE_MSG(rc != -1, 366 "sysctl %s failed: %s", LOCAL_SENDSPACE_SYSCTL, strerror(errno)); |
372 | 367 |
373 if ((buf = calloc(1, sendspace)) == NULL) 374 err(-1, "%s: calloc", test); | 368 buf = calloc(1, sendspace); 369 ATF_REQUIRE(buf != NULL); |
375 | 370 |
376 domainsocketpair(test, fd); 377 if (setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)) < 0) 378 err(-1, "%s: setsockopt(LOCAL_CREDS)", test); 379 tempfile(test, &putfd_1); 380 sendfd_payload(test, fd[0], putfd_1, buf, sendspace); 381 recvfd_payload(test, fd[1], &getfd_1, buf, sendspace); 382 close(putfd_1); 383 close(getfd_1); 384 closesocketpair(fd); 385 } | 371 domainsocketpair(fd); 372 rc = setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)); 373 ATF_REQUIRE_MSG(rc != -1, "setsockopt(LOCAL_CREDS) failed: %s", 374 strerror(errno)); 375 tempfile(&putfd); 376 sendfd_payload(fd[0], putfd, buf, sendspace); 377 recvfd_payload(fd[1], &getfd, buf, sendspace); 378 close(putfd); 379 close(getfd); 380 closesocketpair(fd); 381} |
386 | 382 |
387 printf("%s passed\n", test); | 383ATF_TP_ADD_TCS(tp) 384{ |
388 | 385 |
389 return (0); | 386 ATF_TP_ADD_TC(tp, simple_send_fd); 387 ATF_TP_ADD_TC(tp, send_and_close); 388 ATF_TP_ADD_TC(tp, send_and_cancel); 389 ATF_TP_ADD_TC(tp, two_files); 390 ATF_TP_ADD_TC(tp, bundle); 391 ATF_TP_ADD_TC(tp, bundle_cancel); 392 ATF_TP_ADD_TC(tp, devfs_orphan); 393 ATF_TP_ADD_TC(tp, rights_creds_payload); 394 395 return (atf_no_error()); |
390} | 396} |