1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2020 SUSE LLC <mdoucha@suse.cz>
4 *
5 * CVE-2017-17712
6 *
7 * Test for race condition vulnerability in sendmsg() on SOCK_RAW sockets.
8 * Changing the value of IP_HDRINCL socket option in parallel with sendmsg()
9 * call may lead to uninitialized stack pointer usage, allowing arbitrary code
10 * execution or privilege escalation. Fixed in:
11 *
12 *  commit 8f659a03a0ba9289b9aeb9b4470e6fb263d6f483
13 *  Author: Mohamed Ghannam <simo.ghannam@gmail.com>
14 *  Date:   Sun Dec 10 03:50:58 2017 +0000
15 *
16 *  net: ipv4: fix for a race condition in raw_sendmsg
17 */
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21#include "tst_test.h"
22#include "tst_fuzzy_sync.h"
23
24#define IOVEC_COUNT 4
25#define PACKET_SIZE 100
26
27static int sockfd = -1;
28static struct msghdr msg;
29/* addr must be full of zeroes to trigger the kernel bug */
30static struct sockaddr_in addr;
31static struct iovec iov[IOVEC_COUNT];
32static unsigned char buf[PACKET_SIZE];
33static struct tst_fzsync_pair fzsync_pair;
34
35static void setup(void)
36{
37	int i;
38
39	tst_setup_netns();
40
41	sockfd = SAFE_SOCKET(AF_INET, SOCK_RAW, IPPROTO_ICMP);
42
43	memset(buf, 0xcc, PACKET_SIZE);
44
45	for (i = 0; i < IOVEC_COUNT; i++) {
46		iov[i].iov_base = buf;
47		iov[i].iov_len = PACKET_SIZE;
48	}
49
50	msg.msg_name = &addr;
51	msg.msg_namelen = sizeof(addr);
52	msg.msg_iov = iov;
53	msg.msg_iovlen = IOVEC_COUNT;
54
55	fzsync_pair.exec_loops = 100000;
56	tst_fzsync_pair_init(&fzsync_pair);
57}
58
59static void cleanup(void)
60{
61	if (sockfd > 0)
62		SAFE_CLOSE(sockfd);
63	tst_fzsync_pair_cleanup(&fzsync_pair);
64}
65
66static void *thread_run(void *arg)
67{
68	int val = 0;
69
70	while (tst_fzsync_run_b(&fzsync_pair)) {
71		tst_fzsync_start_race_b(&fzsync_pair);
72		setsockopt(sockfd, SOL_IP, IP_HDRINCL, &val, sizeof(val));
73		tst_fzsync_end_race_b(&fzsync_pair);
74	}
75
76	return arg;
77}
78
79static void run(void)
80{
81	int hdrincl = 1;
82
83	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
84
85	while (tst_fzsync_run_a(&fzsync_pair)) {
86		SAFE_SETSOCKOPT_INT(sockfd, SOL_IP, IP_HDRINCL, hdrincl);
87
88		tst_fzsync_start_race_a(&fzsync_pair);
89		sendmsg(sockfd, &msg, 0);
90		tst_fzsync_end_race_a(&fzsync_pair);
91
92		if (tst_taint_check()) {
93			tst_res(TFAIL, "Kernel is vulnerable");
94			return;
95		}
96	}
97
98	tst_res(TPASS, "Nothing bad happened, probably");
99}
100
101static struct tst_test test = {
102	.test_all = run,
103	.setup = setup,
104	.cleanup = cleanup,
105	.taint_check = TST_TAINT_W | TST_TAINT_D,
106	.max_runtime = 150,
107	.needs_kconfigs = (const char *[]) {
108		"CONFIG_USER_NS=y",
109		"CONFIG_NET_NS=y",
110		NULL
111	},
112	.save_restore = (const struct tst_path_val[]) {
113		{"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP},
114		{}
115	},
116	.tags = (const struct tst_tag[]) {
117		{"linux-git", "8f659a03a0ba"},
118		{"CVE", "2017-17712"},
119		{}
120	}
121};
122