1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com> 4 * Original POC by Daniel Jiang 5 */ 6/* 7 * Test for CVE-2017-2671 faulty locking on ping socket 8 * 9 * When sys_connect() is called with sockaddr.sin_family set to AF_UNSPEC on a 10 * ping socket; __udp_disconnect() gets called, which in turn calls the buggy 11 * function ping_unhashed(). This function does not obtain a rwlock before 12 * checking if the socket is hashed allowing the socket data to be pulled from 13 * underneath it in the time between calling sk_hashed() and gaining the write 14 * lock. 15 * 16 * Fixed in commit 43a6684519ab0a6c52024b5e25322476cabad893 17 * 18 * This test repeatedly 'connects' a ping socket correctly then calls 19 * connect() with AF_UNSPEC in two seperate threads to trigger the race 20 * condition. If the bug is present, then the test will most likely crash the 21 * system. 22 * 23 * The test requests root privileges so that it can ensure ping sockets are 24 * enabled. On distributions (including Android) where ping sockets are 25 * enabled by default, root privileges are not required. 26 */ 27 28#include <unistd.h> 29#include <stdio.h> 30#include <sys/socket.h> 31#include <arpa/inet.h> 32#include <stdlib.h> 33 34#include "tst_test.h" 35#include "tst_safe_net.h" 36#include "tst_safe_pthread.h" 37 38#include "tst_fuzzy_sync.h" 39 40#define ATTEMPTS 0x80000 41#define PING_SYSCTL_PATH "/proc/sys/net/ipv4/ping_group_range" 42 43static int sockfd; 44static unsigned int ping_min_grp, ping_max_grp; 45static struct tst_fzsync_pair fzsync_pair; 46static struct sockaddr_in iaddr, uaddr; 47static void *connect_b(void *); 48 49static void setup(void) 50{ 51 iaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 52 uaddr = iaddr; 53 iaddr.sin_family = AF_INET; 54 uaddr.sin_family = AF_UNSPEC; 55 56 if (access(PING_SYSCTL_PATH, F_OK)) 57 tst_brk(TCONF, "socket() does not support IPPROTO_ICMP"); 58 59 SAFE_FILE_SCANF(PING_SYSCTL_PATH, "%u %u", 60 &ping_min_grp, &ping_max_grp); 61 SAFE_FILE_PRINTF(PING_SYSCTL_PATH, "0 0"); 62 63 sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 64 tst_res(TINFO, "Created ping socket, attempting to race..."); 65 66 tst_fzsync_pair_init(&fzsync_pair); 67} 68 69static void cleanup(void) 70{ 71 tst_fzsync_pair_cleanup(&fzsync_pair); 72 73 if (sockfd > 0) 74 SAFE_CLOSE(sockfd); 75 76 if (ping_min_grp | ping_max_grp) 77 SAFE_FILE_PRINTF(PING_SYSCTL_PATH, "%u %u", 78 ping_min_grp, ping_max_grp); 79} 80 81static void *connect_b(void * param LTP_ATTRIBUTE_UNUSED) 82{ 83 while (tst_fzsync_run_b(&fzsync_pair)) { 84 tst_fzsync_start_race_b(&fzsync_pair); 85 connect(sockfd, (struct sockaddr *)&uaddr, sizeof(uaddr)); 86 tst_fzsync_end_race_b(&fzsync_pair); 87 } 88 89 return 0; 90} 91 92static void run(void) 93{ 94 tst_fzsync_pair_reset(&fzsync_pair, connect_b); 95 while (tst_fzsync_run_a(&fzsync_pair)) { 96 SAFE_CONNECT(sockfd, 97 (struct sockaddr *)&iaddr, sizeof(iaddr)); 98 99 tst_fzsync_start_race_a(&fzsync_pair); 100 connect(sockfd, (struct sockaddr *)&uaddr, sizeof(uaddr)); 101 tst_fzsync_end_race_a(&fzsync_pair); 102 } 103 104 tst_res(TPASS, "We didn't crash"); 105} 106 107static struct tst_test test = { 108 .setup = setup, 109 .test_all = run, 110 .cleanup = cleanup, 111 .needs_root = 1, 112 .max_runtime = 40, 113 .tags = (const struct tst_tag[]) { 114 {"linux-git", "43a6684519ab"}, 115 {"CVE", "2017-2671"}, 116 {} 117 } 118}; 119