]>
Commit | Line | Data |
---|---|---|
4ba76501 A |
1 | #include <stdint.h> |
2 | #include <stdio.h> | |
3 | #include <stdlib.h> | |
4 | #include <string.h> | |
5 | ||
6 | #include <arpa/inet.h> | |
7 | #include <fcntl.h> | |
8 | #include <pthread.h> | |
9 | #include <netinet/in.h> | |
10 | #include <sys/ioctl.h> | |
11 | #include <sys/socket.h> | |
12 | #include <unistd.h> | |
13 | ||
14 | #include <darwintest.h> | |
15 | ||
16 | /* sizeof(struct ip6_pktopts) */ | |
17 | #define SIZEOF_STRUCT_IP6_PKTOPTS 192 | |
18 | ||
19 | static int finished = 0; | |
20 | ||
21 | static void * | |
22 | setopt_thread(void *data) | |
23 | { | |
24 | int s = *(int *)data; | |
25 | uint8_t optbuf[CMSG_LEN(0)]; | |
26 | uint8_t spraybuf[SIZEOF_STRUCT_IP6_PKTOPTS]; | |
27 | ||
28 | memset(optbuf, 0, sizeof(optbuf)); | |
29 | memset(spraybuf, 0x41, sizeof(spraybuf)); | |
30 | ||
31 | while (!finished) { | |
32 | T_ASSERT_POSIX_SUCCESS(setsockopt(s, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, optbuf, sizeof(optbuf)), NULL); | |
33 | ||
34 | /* force an error to free: */ | |
35 | T_ASSERT_EQ(setsockopt(s, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, optbuf, 1), -1, NULL); | |
36 | ||
37 | /* realloc: */ | |
38 | T_ASSERT_EQ(ioctl(-1, _IOW('x', 0, spraybuf), spraybuf), -1, NULL); | |
39 | } | |
40 | ||
41 | return NULL; | |
42 | } | |
43 | ||
44 | static void * | |
45 | connect_thread(void *data) | |
46 | { | |
47 | struct sockaddr_in6 *dst = data; | |
48 | int s; | |
49 | ||
50 | while (!finished) { | |
51 | T_ASSERT_POSIX_SUCCESS(s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP), NULL); | |
52 | connect(s, (const struct sockaddr *)dst, sizeof(*dst)); | |
53 | close(s); | |
54 | } | |
55 | ||
56 | return NULL; | |
57 | } | |
58 | ||
59 | T_DECL(tcp_input_outputopts_uaf_56155583, "Use-after-free when accepting TCP6 connections.") | |
60 | { | |
61 | int s; | |
62 | struct sockaddr_in6 sin6 = { | |
63 | .sin6_family = AF_INET6, | |
64 | .sin6_port = htons(1337) | |
65 | }; | |
66 | struct sockaddr_in6 addr; | |
67 | socklen_t addr_len; | |
68 | pthread_t threads[20]; | |
69 | int nthreads = 0; | |
70 | int n; | |
71 | ||
72 | T_SETUPBEGIN; | |
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); | |
78 | T_SETUPEND; | |
79 | ||
80 | for (n = 0; n < 16; ++n) { | |
81 | if (pthread_create(&threads[nthreads++], NULL, setopt_thread, &s)) { | |
82 | T_ASSERT_FAIL("pthread_create failed"); | |
83 | } | |
84 | } | |
85 | ||
86 | for (n = 0; n < 4; ++n) { | |
87 | if (pthread_create(&threads[nthreads++], NULL, connect_thread, &sin6)) { | |
88 | T_ASSERT_FAIL("pthread_create failed"); | |
89 | } | |
90 | } | |
91 | ||
92 | for (n = 0; n < 200000; ++n) { | |
93 | addr_len = sizeof(addr); | |
94 | close(accept(s, (struct sockaddr *)&addr, &addr_len)); | |
95 | } | |
96 | ||
97 | finished = 1; | |
98 | ||
99 | for (n = 0; n < nthreads; ++n) { | |
100 | pthread_join(threads[n], NULL); | |
101 | } | |
102 | } |