You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
3.8 KiB
151 lines
3.8 KiB
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2019 SUSE LLC
|
|
* Author: Christian Amann <camann@suse.com>
|
|
*/
|
|
/* Test for CVE-2017-8890
|
|
*
|
|
* In Kernels up to 4.10.15 missing commit 657831ff the multicast
|
|
* group information of a socket gets copied over to a newly created
|
|
* socket when using the accept() syscall. This will cause a double free
|
|
* when closing the original and the cloned socket.
|
|
*
|
|
* WARNING:
|
|
* There is a high chance that this test will cause an unstable system
|
|
* if it does not succeed!
|
|
*
|
|
* For more information about this CVE see:
|
|
* https://www.suse.com/security/cve/CVE-2017-8890/
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <sys/socket.h>
|
|
#include "tst_test.h"
|
|
#include "tst_safe_net.h"
|
|
#include "tst_safe_pthread.h"
|
|
|
|
#define MULTICASTIP "224.0.0.0"
|
|
#define LOCALHOSTIP "127.0.0.1"
|
|
|
|
static int server_sockfd;
|
|
static int clone_server_sockfd;
|
|
static int client_sockfd;
|
|
static int server_port;
|
|
static socklen_t addr_len;
|
|
|
|
static struct sockaddr_in *server_addr;
|
|
static struct sockaddr_in *client_addr;
|
|
static struct group_req *mc_group;
|
|
|
|
static void *server_thread(void *arg)
|
|
{
|
|
int op, op_len, mc_group_len;
|
|
|
|
op = 1;
|
|
op_len = sizeof(op);
|
|
mc_group_len = sizeof(*mc_group);
|
|
|
|
server_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
|
|
|
|
SAFE_SETSOCKOPT(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, op_len);
|
|
SAFE_SETSOCKOPT(server_sockfd, SOL_IP, MCAST_JOIN_GROUP,
|
|
mc_group, mc_group_len);
|
|
|
|
SAFE_BIND(server_sockfd, (struct sockaddr *)server_addr, addr_len);
|
|
SAFE_LISTEN(server_sockfd, 1);
|
|
|
|
TST_CHECKPOINT_WAKE(0);
|
|
|
|
TEST(accept(server_sockfd, (struct sockaddr *)client_addr, &addr_len));
|
|
if (TST_RET == -1)
|
|
tst_brk(TBROK | TTERRNO, "Could not accept connection");
|
|
|
|
clone_server_sockfd = TST_RET;
|
|
|
|
TEST(setsockopt(clone_server_sockfd, SOL_IP, MCAST_LEAVE_GROUP,
|
|
mc_group, mc_group_len));
|
|
|
|
if (TST_RET != -1)
|
|
tst_res(TFAIL, "Multicast group was copied!");
|
|
else if (TST_ERR == EADDRNOTAVAIL)
|
|
tst_res(TPASS | TTERRNO, "Multicast group was not copied");
|
|
else
|
|
tst_brk(TBROK | TTERRNO, "setsockopt() failed unexpectedly");
|
|
|
|
SAFE_CLOSE(server_sockfd);
|
|
return arg;
|
|
}
|
|
|
|
static void *client_thread(void *arg)
|
|
{
|
|
client_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
|
|
SAFE_BIND(client_sockfd, (struct sockaddr *)client_addr, addr_len);
|
|
|
|
SAFE_CONNECT(client_sockfd, (struct sockaddr *)server_addr, addr_len);
|
|
|
|
SAFE_CLOSE(client_sockfd);
|
|
return arg;
|
|
}
|
|
|
|
static void run(void)
|
|
{
|
|
pthread_t server_thr, client_thr;
|
|
|
|
server_addr->sin_port = server_port;
|
|
client_addr->sin_port = htons(0);
|
|
|
|
SAFE_PTHREAD_CREATE(&server_thr, NULL, server_thread, NULL);
|
|
TST_CHECKPOINT_WAIT(0);
|
|
SAFE_PTHREAD_CREATE(&client_thr, NULL, client_thread, NULL);
|
|
|
|
SAFE_PTHREAD_JOIN(server_thr, NULL);
|
|
SAFE_PTHREAD_JOIN(client_thr, NULL);
|
|
}
|
|
|
|
static void setup(void)
|
|
{
|
|
struct sockaddr_in *mc_group_addr;
|
|
|
|
server_addr = tst_alloc(sizeof(*server_addr));
|
|
client_addr = tst_alloc(sizeof(*client_addr));
|
|
mc_group = tst_alloc(sizeof(*mc_group));
|
|
|
|
mc_group->gr_interface = 0;
|
|
mc_group_addr = (struct sockaddr_in *) &mc_group->gr_group;
|
|
mc_group_addr->sin_family = AF_INET;
|
|
inet_aton(MULTICASTIP, &mc_group_addr->sin_addr);
|
|
|
|
server_addr->sin_family = AF_INET;
|
|
inet_aton(LOCALHOSTIP, &server_addr->sin_addr);
|
|
|
|
client_addr->sin_family = AF_INET;
|
|
client_addr->sin_addr.s_addr = htons(INADDR_ANY);
|
|
|
|
addr_len = sizeof(struct sockaddr_in);
|
|
|
|
server_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
|
|
tst_res(TINFO, "Starting listener on port: %d", ntohs(server_port));
|
|
}
|
|
|
|
static void cleanup(void)
|
|
{
|
|
if (clone_server_sockfd > 0)
|
|
SAFE_CLOSE(clone_server_sockfd);
|
|
if (client_sockfd > 0)
|
|
SAFE_CLOSE(client_sockfd);
|
|
if (server_sockfd > 0)
|
|
SAFE_CLOSE(server_sockfd);
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.test_all = run,
|
|
.setup = setup,
|
|
.cleanup = cleanup,
|
|
.needs_checkpoints = 1,
|
|
.tags = (const struct tst_tag[]) {
|
|
{"CVE", "2017-8890"},
|
|
{"linux-git", "657831ff"},
|
|
{},
|
|
}
|
|
};
|