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