9 #include <netinet/in.h>
10 #include <sys/ioctl.h>
11 #include <sys/socket.h>
14 #include <darwintest.h>
16 /* sizeof(struct ip6_pktopts) */
17 #define SIZEOF_STRUCT_IP6_PKTOPTS 192
19 static int finished
= 0;
22 setopt_thread(void *data
)
25 uint8_t optbuf
[CMSG_LEN(0)];
26 uint8_t spraybuf
[SIZEOF_STRUCT_IP6_PKTOPTS
];
28 memset(optbuf
, 0, sizeof(optbuf
));
29 memset(spraybuf
, 0x41, sizeof(spraybuf
));
32 T_ASSERT_POSIX_SUCCESS(setsockopt(s
, IPPROTO_IPV6
, IPV6_2292PKTOPTIONS
, optbuf
, sizeof(optbuf
)), NULL
);
34 /* force an error to free: */
35 T_ASSERT_EQ(setsockopt(s
, IPPROTO_IPV6
, IPV6_2292PKTOPTIONS
, optbuf
, 1), -1, NULL
);
38 T_ASSERT_EQ(ioctl(-1, _IOW('x', 0, spraybuf
), spraybuf
), -1, NULL
);
45 connect_thread(void *data
)
47 struct sockaddr_in6
*dst
= data
;
51 T_ASSERT_POSIX_SUCCESS(s
= socket(AF_INET6
, SOCK_STREAM
, IPPROTO_TCP
), NULL
);
52 connect(s
, (const struct sockaddr
*)dst
, sizeof(*dst
));
59 T_DECL(tcp_input_outputopts_uaf_56155583
, "Use-after-free when accepting TCP6 connections.")
62 struct sockaddr_in6 sin6
= {
63 .sin6_family
= AF_INET6
,
64 .sin6_port
= htons(1337)
66 struct sockaddr_in6 addr
;
68 pthread_t threads
[20];
73 T_ASSERT_EQ(inet_pton(AF_INET6
, "::1", &sin6
.sin6_addr
), 1, NULL
);
74 T_ASSERT_POSIX_SUCCESS(s
= socket(AF_INET6
, SOCK_STREAM
, IPPROTO_TCP
), NULL
);
75 T_ASSERT_POSIX_SUCCESS(bind(s
, (const struct sockaddr
*)&sin6
, sizeof(sin6
)), NULL
);
76 T_ASSERT_POSIX_SUCCESS(listen(s
, 32), NULL
);
77 T_ASSERT_POSIX_SUCCESS(fcntl(s
, F_SETFL
, fcntl(s
, F_GETFL
) | O_NONBLOCK
), NULL
);
80 for (n
= 0; n
< 16; ++n
) {
81 if (pthread_create(&threads
[nthreads
++], NULL
, setopt_thread
, &s
)) {
82 T_ASSERT_FAIL("pthread_create failed");
86 for (n
= 0; n
< 4; ++n
) {
87 if (pthread_create(&threads
[nthreads
++], NULL
, connect_thread
, &sin6
)) {
88 T_ASSERT_FAIL("pthread_create failed");
92 for (n
= 0; n
< 200000; ++n
) {
93 addr_len
= sizeof(addr
);
94 close(accept(s
, (struct sockaddr
*)&addr
, &addr_len
));
99 for (n
= 0; n
< nthreads
; ++n
) {
100 pthread_join(threads
[n
], NULL
);