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