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