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