1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * CVE-2017-1000111
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Check for race condition between packet_set_ring() and tp_reserve.
10f08c3bdfSopenharmony_ci * The race allows you to set tp_reserve bigger than ring buffer size.
11f08c3bdfSopenharmony_ci * While this will cause truncation of all incoming packets to 0 bytes,
12f08c3bdfSopenharmony_ci * sanity checks in tpacket_rcv() prevent any exploitable buffer overflows.
13f08c3bdfSopenharmony_ci * Race fixed in:
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *  commit c27927e372f0785f3303e8fad94b85945e2c97b7 (HEAD)
16f08c3bdfSopenharmony_ci *  Author: Willem de Bruijn <willemb@google.com>
17f08c3bdfSopenharmony_ci *  Date:   Thu Aug 10 12:41:58 2017 -0400
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci *  packet: fix tp_reserve race in packet_set_ring
20f08c3bdfSopenharmony_ci */
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_ci#include <unistd.h>
23f08c3bdfSopenharmony_ci#include <sys/types.h>
24f08c3bdfSopenharmony_ci#include <sys/socket.h>
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#include "tst_test.h"
27f08c3bdfSopenharmony_ci#include "tst_fuzzy_sync.h"
28f08c3bdfSopenharmony_ci#include "lapi/if_packet.h"
29f08c3bdfSopenharmony_ci#include "lapi/if_ether.h"
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic int sock = -1;
32f08c3bdfSopenharmony_cistatic unsigned int pagesize;
33f08c3bdfSopenharmony_cistatic struct tst_fzsync_pair fzsync_pair;
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_cistatic void setup(void)
36f08c3bdfSopenharmony_ci{
37f08c3bdfSopenharmony_ci	pagesize = SAFE_SYSCONF(_SC_PAGESIZE);
38f08c3bdfSopenharmony_ci	tst_setup_netns();
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	/*
41f08c3bdfSopenharmony_ci	 * Reproducing the bug on unpatched system takes <15 loops. The test
42f08c3bdfSopenharmony_ci	 * is slow and the bug is mostly harmless so don't waste too much
43f08c3bdfSopenharmony_ci	 * time.
44f08c3bdfSopenharmony_ci	 */
45f08c3bdfSopenharmony_ci	fzsync_pair.exec_loops = 500;
46f08c3bdfSopenharmony_ci	tst_fzsync_pair_init(&fzsync_pair);
47f08c3bdfSopenharmony_ci}
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_cistatic void *thread_run(void *arg)
50f08c3bdfSopenharmony_ci{
51f08c3bdfSopenharmony_ci	unsigned int val = 1 << 30;
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	while (tst_fzsync_run_b(&fzsync_pair)) {
54f08c3bdfSopenharmony_ci		tst_fzsync_start_race_b(&fzsync_pair);
55f08c3bdfSopenharmony_ci		setsockopt(sock, SOL_PACKET, PACKET_RESERVE, &val, sizeof(val));
56f08c3bdfSopenharmony_ci		tst_fzsync_end_race_b(&fzsync_pair);
57f08c3bdfSopenharmony_ci	}
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	return arg;
60f08c3bdfSopenharmony_ci}
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_cistatic void run(void)
63f08c3bdfSopenharmony_ci{
64f08c3bdfSopenharmony_ci	unsigned int val, version = TPACKET_V3;
65f08c3bdfSopenharmony_ci	socklen_t vsize = sizeof(val);
66f08c3bdfSopenharmony_ci	struct tpacket_req3 req = {
67f08c3bdfSopenharmony_ci		.tp_block_size = pagesize,
68f08c3bdfSopenharmony_ci		.tp_block_nr = 1,
69f08c3bdfSopenharmony_ci		.tp_frame_size = pagesize,
70f08c3bdfSopenharmony_ci		.tp_frame_nr = 1,
71f08c3bdfSopenharmony_ci		.tp_retire_blk_tov = 100
72f08c3bdfSopenharmony_ci	};
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	while (tst_fzsync_run_a(&fzsync_pair)) {
77f08c3bdfSopenharmony_ci		sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
78f08c3bdfSopenharmony_ci		TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &version,
79f08c3bdfSopenharmony_ci			sizeof(version)));
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci		if (TST_RET == -1 && TST_ERR == EINVAL)
82f08c3bdfSopenharmony_ci			tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci		if (TST_RET) {
85f08c3bdfSopenharmony_ci			tst_brk(TBROK | TTERRNO,
86f08c3bdfSopenharmony_ci				"setsockopt(PACKET_VERSION, TPACKET_V3");
87f08c3bdfSopenharmony_ci		}
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci		tst_fzsync_start_race_a(&fzsync_pair);
90f08c3bdfSopenharmony_ci		TEST(setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req,
91f08c3bdfSopenharmony_ci			sizeof(req)));
92f08c3bdfSopenharmony_ci		tst_fzsync_end_race_a(&fzsync_pair);
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci		SAFE_GETSOCKOPT(sock, SOL_PACKET, PACKET_RESERVE, &val, &vsize);
95f08c3bdfSopenharmony_ci		SAFE_CLOSE(sock);
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci		if (TST_RET == -1 && TST_ERR == EINVAL) {
98f08c3bdfSopenharmony_ci			tst_fzsync_pair_add_bias(&fzsync_pair, 1);
99f08c3bdfSopenharmony_ci			continue;
100f08c3bdfSopenharmony_ci		}
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci		if (TST_RET) {
103f08c3bdfSopenharmony_ci			tst_brk(TBROK | TTERRNO,
104f08c3bdfSopenharmony_ci				"Invalid setsockopt() return value");
105f08c3bdfSopenharmony_ci		}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci		if (val > req.tp_block_size) {
108f08c3bdfSopenharmony_ci			tst_res(TFAIL, "PACKET_RESERVE checks bypassed");
109f08c3bdfSopenharmony_ci			return;
110f08c3bdfSopenharmony_ci		}
111f08c3bdfSopenharmony_ci	}
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ci	tst_res(TPASS, "Cannot reproduce bug");
114f08c3bdfSopenharmony_ci}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_cistatic void cleanup(void)
117f08c3bdfSopenharmony_ci{
118f08c3bdfSopenharmony_ci	tst_fzsync_pair_cleanup(&fzsync_pair);
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci	if (sock >= 0)
121f08c3bdfSopenharmony_ci		SAFE_CLOSE(sock);
122f08c3bdfSopenharmony_ci}
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_cistatic struct tst_test test = {
125f08c3bdfSopenharmony_ci	.test_all = run,
126f08c3bdfSopenharmony_ci	.setup = setup,
127f08c3bdfSopenharmony_ci	.cleanup = cleanup,
128f08c3bdfSopenharmony_ci	.max_runtime = 150,
129f08c3bdfSopenharmony_ci	.needs_kconfigs = (const char *[]) {
130f08c3bdfSopenharmony_ci		"CONFIG_USER_NS=y",
131f08c3bdfSopenharmony_ci		"CONFIG_NET_NS=y",
132f08c3bdfSopenharmony_ci		NULL
133f08c3bdfSopenharmony_ci	},
134f08c3bdfSopenharmony_ci	.save_restore = (const struct tst_path_val[]) {
135f08c3bdfSopenharmony_ci		{"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP},
136f08c3bdfSopenharmony_ci		{}
137f08c3bdfSopenharmony_ci	},
138f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
139f08c3bdfSopenharmony_ci		{"linux-git", "c27927e372f0"},
140f08c3bdfSopenharmony_ci		{"CVE", "2017-1000111"},
141f08c3bdfSopenharmony_ci		{}
142f08c3bdfSopenharmony_ci	}
143f08c3bdfSopenharmony_ci};
144