Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
* Original POC by Daniel Jiang
*/
/*
* Test for CVE-2017-2671 faulty locking on ping socket
*
* When sys_connect() is called with sockaddr.sin_family set to AF_UNSPEC on a
* ping socket; __udp_disconnect() gets called, which in turn calls the buggy
* function ping_unhashed(). This function does not obtain a rwlock before
* checking if the socket is hashed allowing the socket data to be pulled from
* underneath it in the time between calling sk_hashed() and gaining the write
* lock.
*
* Fixed in commit 43a6684519ab0a6c52024b5e25322476cabad893
*
* This test repeatedly 'connects' a ping socket correctly then calls
* connect() with AF_UNSPEC in two seperate threads to trigger the race
* condition. If the bug is present, then the test will most likely crash the
* system.
*
* The test requests root privileges so that it can ensure ping sockets are
* enabled. On distributions (including Android) where ping sockets are
* enabled by default, root privileges are not required.
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include "tst_test.h"
#include "tst_safe_net.h"
#include "tst_safe_pthread.h"
#include "tst_fuzzy_sync.h"
#define ATTEMPTS 0x80000
#define PING_SYSCTL_PATH "/proc/sys/net/ipv4/ping_group_range"
static int sockfd;
static unsigned int ping_min_grp, ping_max_grp;
static struct tst_fzsync_pair fzsync_pair;
static struct sockaddr_in iaddr, uaddr;
static void *connect_b(void *);
static void setup(void)
{
iaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
uaddr = iaddr;
iaddr.sin_family = AF_INET;
uaddr.sin_family = AF_UNSPEC;
if (access(PING_SYSCTL_PATH, F_OK))
tst_brk(TCONF, "socket() does not support IPPROTO_ICMP");
SAFE_FILE_SCANF(PING_SYSCTL_PATH, "%u %u",
&ping_min_grp, &ping_max_grp);
SAFE_FILE_PRINTF(PING_SYSCTL_PATH, "0 0");
sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
tst_res(TINFO, "Created ping socket, attempting to race...");
tst_fzsync_pair_init(&fzsync_pair);
}
static void cleanup(void)
{
tst_fzsync_pair_cleanup(&fzsync_pair);
if (sockfd > 0)
SAFE_CLOSE(sockfd);
if (ping_min_grp | ping_max_grp)
SAFE_FILE_PRINTF(PING_SYSCTL_PATH, "%u %u",
ping_min_grp, ping_max_grp);
}
static void *connect_b(void * param LTP_ATTRIBUTE_UNUSED)
{
while (tst_fzsync_run_b(&fzsync_pair)) {
tst_fzsync_start_race_b(&fzsync_pair);
connect(sockfd, (struct sockaddr *)&uaddr, sizeof(uaddr));
tst_fzsync_end_race_b(&fzsync_pair);
}
return 0;
}
static void run(void)
{
tst_fzsync_pair_reset(&fzsync_pair, connect_b);
while (tst_fzsync_run_a(&fzsync_pair)) {
SAFE_CONNECT(sockfd,
(struct sockaddr *)&iaddr, sizeof(iaddr));
tst_fzsync_start_race_a(&fzsync_pair);
connect(sockfd, (struct sockaddr *)&uaddr, sizeof(uaddr));
tst_fzsync_end_race_a(&fzsync_pair);
}
tst_res(TPASS, "We didn't crash");
}
static struct tst_test test = {
.setup = setup,
.test_all = run,
.cleanup = cleanup,
.needs_root = 1,
.max_runtime = 40,
.tags = (const struct tst_tag[]) {
{"linux-git", "43a6684519ab"},
{"CVE", "2017-2671"},
{}
}
};