1*4d495c6eSApple OSS Distributions /* This tests thread_t uaf vulnerability in the XNU kernel due to
2*4d495c6eSApple OSS Distributions * a race condition in unp_connect
3*4d495c6eSApple OSS Distributions */
4*4d495c6eSApple OSS Distributions
5*4d495c6eSApple OSS Distributions #include <sys/un.h>
6*4d495c6eSApple OSS Distributions #include <sys/socket.h>
7*4d495c6eSApple OSS Distributions #include <pthread.h>
8*4d495c6eSApple OSS Distributions #include <sys/proc_info.h>
9*4d495c6eSApple OSS Distributions #include <libproc.h>
10*4d495c6eSApple OSS Distributions #include <darwintest.h>
11*4d495c6eSApple OSS Distributions #include <unistd.h>
12*4d495c6eSApple OSS Distributions
13*4d495c6eSApple OSS Distributions #include "net_test_lib.h"
14*4d495c6eSApple OSS Distributions
15*4d495c6eSApple OSS Distributions int g_start = 0;
16*4d495c6eSApple OSS Distributions int g_client = 0;
17*4d495c6eSApple OSS Distributions int g_sever1 = 0;
18*4d495c6eSApple OSS Distributions int g_sever2 = 0;
19*4d495c6eSApple OSS Distributions
20*4d495c6eSApple OSS Distributions static void
server_thread1(char * path)21*4d495c6eSApple OSS Distributions server_thread1(char* path)
22*4d495c6eSApple OSS Distributions {
23*4d495c6eSApple OSS Distributions struct sockaddr_un server_sockaddr;
24*4d495c6eSApple OSS Distributions memset(&server_sockaddr, 0, sizeof(struct sockaddr_un));
25*4d495c6eSApple OSS Distributions server_sockaddr.sun_family = AF_UNIX;
26*4d495c6eSApple OSS Distributions strcpy(server_sockaddr.sun_path, path);
27*4d495c6eSApple OSS Distributions unlink(server_sockaddr.sun_path);
28*4d495c6eSApple OSS Distributions
29*4d495c6eSApple OSS Distributions int server_sock = socket(AF_UNIX, SOCK_STREAM, 0);
30*4d495c6eSApple OSS Distributions g_sever1 = server_sock;
31*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(bind(server_sock,
32*4d495c6eSApple OSS Distributions (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr)), NULL);
33*4d495c6eSApple OSS Distributions
34*4d495c6eSApple OSS Distributions /*********************************/
35*4d495c6eSApple OSS Distributions /* Listen for any client sockets */
36*4d495c6eSApple OSS Distributions /*********************************/
37*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(listen(server_sock, -1), NULL);
38*4d495c6eSApple OSS Distributions
39*4d495c6eSApple OSS Distributions return;
40*4d495c6eSApple OSS Distributions }
41*4d495c6eSApple OSS Distributions
42*4d495c6eSApple OSS Distributions static void
server_thread2(char * path)43*4d495c6eSApple OSS Distributions server_thread2(char* path)
44*4d495c6eSApple OSS Distributions {
45*4d495c6eSApple OSS Distributions struct sockaddr_un server_sockaddr;
46*4d495c6eSApple OSS Distributions memset(&server_sockaddr, 0, sizeof(struct sockaddr_un));
47*4d495c6eSApple OSS Distributions server_sockaddr.sun_family = AF_UNIX;
48*4d495c6eSApple OSS Distributions strcpy(server_sockaddr.sun_path, path);
49*4d495c6eSApple OSS Distributions unlink(server_sockaddr.sun_path);
50*4d495c6eSApple OSS Distributions
51*4d495c6eSApple OSS Distributions int server_sock = socket(AF_UNIX, SOCK_STREAM, 0);
52*4d495c6eSApple OSS Distributions g_sever2 = server_sock;
53*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(bind(server_sock,
54*4d495c6eSApple OSS Distributions (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr)), NULL);
55*4d495c6eSApple OSS Distributions
56*4d495c6eSApple OSS Distributions /*********************************/
57*4d495c6eSApple OSS Distributions /* Listen for any client sockets */
58*4d495c6eSApple OSS Distributions /*********************************/
59*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(listen(server_sock, -1), NULL);
60*4d495c6eSApple OSS Distributions
61*4d495c6eSApple OSS Distributions return;
62*4d495c6eSApple OSS Distributions }
63*4d495c6eSApple OSS Distributions
64*4d495c6eSApple OSS Distributions static void
try_to_connect(char * path)65*4d495c6eSApple OSS Distributions try_to_connect(char* path)
66*4d495c6eSApple OSS Distributions {
67*4d495c6eSApple OSS Distributions struct sockaddr_un server_sockaddr;
68*4d495c6eSApple OSS Distributions memset(&server_sockaddr, 0, sizeof(struct sockaddr_un));
69*4d495c6eSApple OSS Distributions server_sockaddr.sun_family = AF_UNIX;
70*4d495c6eSApple OSS Distributions strcpy(server_sockaddr.sun_path, path);
71*4d495c6eSApple OSS Distributions //unlink(server_sockaddr.sun_path);
72*4d495c6eSApple OSS Distributions
73*4d495c6eSApple OSS Distributions while (g_start == 0) {
74*4d495c6eSApple OSS Distributions usleep(100);
75*4d495c6eSApple OSS Distributions }
76*4d495c6eSApple OSS Distributions int ret = connect(g_client, (struct sockaddr *)&server_sockaddr,
77*4d495c6eSApple OSS Distributions sizeof(server_sockaddr));
78*4d495c6eSApple OSS Distributions
79*4d495c6eSApple OSS Distributions T_ASSERT_TRUE(ret == 0 || errno == EALREADY || errno == EISCONN,
80*4d495c6eSApple OSS Distributions "connect with ret: %d(%d)", ret, errno);
81*4d495c6eSApple OSS Distributions }
82*4d495c6eSApple OSS Distributions
83*4d495c6eSApple OSS Distributions
84*4d495c6eSApple OSS Distributions static void
test_unp_connect_multithread()85*4d495c6eSApple OSS Distributions test_unp_connect_multithread()
86*4d495c6eSApple OSS Distributions {
87*4d495c6eSApple OSS Distributions int client_sock;
88*4d495c6eSApple OSS Distributions char path[] = "/tmp/";
89*4d495c6eSApple OSS Distributions char path1[256];
90*4d495c6eSApple OSS Distributions char path2[256];
91*4d495c6eSApple OSS Distributions char path3[256];
92*4d495c6eSApple OSS Distributions
93*4d495c6eSApple OSS Distributions strncpy(path1, path, 255);
94*4d495c6eSApple OSS Distributions strcat(path1, "/1");
95*4d495c6eSApple OSS Distributions strncpy(path2, path, 255);
96*4d495c6eSApple OSS Distributions strcat(path2, "/2");
97*4d495c6eSApple OSS Distributions strncpy(path3, path, 255);
98*4d495c6eSApple OSS Distributions strcat(path3, "/3");
99*4d495c6eSApple OSS Distributions
100*4d495c6eSApple OSS Distributions
101*4d495c6eSApple OSS Distributions for (int i = 0; i < 1024; i++) {
102*4d495c6eSApple OSS Distributions T_SETUPBEGIN;
103*4d495c6eSApple OSS Distributions server_thread1(path1);
104*4d495c6eSApple OSS Distributions server_thread2(path2);
105*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(client_sock = socket(AF_UNIX, SOCK_STREAM, 0), NULL);
106*4d495c6eSApple OSS Distributions
107*4d495c6eSApple OSS Distributions unlink(path3);
108*4d495c6eSApple OSS Distributions struct sockaddr_un client_sockaddr;
109*4d495c6eSApple OSS Distributions client_sockaddr.sun_family = AF_UNIX;
110*4d495c6eSApple OSS Distributions strcpy(client_sockaddr.sun_path, path3);
111*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(bind(client_sock, (struct sockaddr *)&client_sockaddr,
112*4d495c6eSApple OSS Distributions sizeof(client_sockaddr)), NULL);
113*4d495c6eSApple OSS Distributions T_SETUPEND;
114*4d495c6eSApple OSS Distributions g_client = client_sock;
115*4d495c6eSApple OSS Distributions g_start = 0;
116*4d495c6eSApple OSS Distributions pthread_t runner1;
117*4d495c6eSApple OSS Distributions pthread_t runner2;
118*4d495c6eSApple OSS Distributions if (pthread_create(&runner1, 0, (void*)try_to_connect, path1)) {
119*4d495c6eSApple OSS Distributions T_ASSERT_FAIL("pthread_create failed");
120*4d495c6eSApple OSS Distributions }
121*4d495c6eSApple OSS Distributions
122*4d495c6eSApple OSS Distributions if (pthread_create(&runner2, 0, (void*)try_to_connect, path2)) {
123*4d495c6eSApple OSS Distributions T_ASSERT_FAIL("pthread_create failed");
124*4d495c6eSApple OSS Distributions }
125*4d495c6eSApple OSS Distributions usleep(300);
126*4d495c6eSApple OSS Distributions g_start = 1;
127*4d495c6eSApple OSS Distributions pthread_join(runner1, 0);
128*4d495c6eSApple OSS Distributions pthread_join(runner2, 0);
129*4d495c6eSApple OSS Distributions
130*4d495c6eSApple OSS Distributions usleep(3000);
131*4d495c6eSApple OSS Distributions
132*4d495c6eSApple OSS Distributions struct socket_fdinfo si_1 = {0};
133*4d495c6eSApple OSS Distributions proc_pidfdinfo(getpid(), g_sever1, PROC_PIDFDSOCKETINFO, &si_1,
134*4d495c6eSApple OSS Distributions sizeof(si_1));
135*4d495c6eSApple OSS Distributions struct socket_fdinfo si_2 = {0};
136*4d495c6eSApple OSS Distributions proc_pidfdinfo(getpid(), g_sever2, PROC_PIDFDSOCKETINFO, &si_2,
137*4d495c6eSApple OSS Distributions sizeof(si_2));
138*4d495c6eSApple OSS Distributions if (si_1.psi.soi_incqlen || si_2.psi.soi_incqlen) {
139*4d495c6eSApple OSS Distributions close(g_sever2);
140*4d495c6eSApple OSS Distributions close(g_sever1);
141*4d495c6eSApple OSS Distributions }
142*4d495c6eSApple OSS Distributions close(client_sock);
143*4d495c6eSApple OSS Distributions close(g_sever2);
144*4d495c6eSApple OSS Distributions close(g_sever1);
145*4d495c6eSApple OSS Distributions }
146*4d495c6eSApple OSS Distributions
147*4d495c6eSApple OSS Distributions force_zone_gc();
148*4d495c6eSApple OSS Distributions }
149*4d495c6eSApple OSS Distributions
150*4d495c6eSApple OSS Distributions T_DECL(unp_connect_thread_uaf, "Uaf due to multithreaded unp_connect", T_META_TAG_VM_PREFERRED)
151*4d495c6eSApple OSS Distributions {
152*4d495c6eSApple OSS Distributions test_unp_connect_multithread();
153*4d495c6eSApple OSS Distributions }
154