1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci/* Test for CVE-2017-7308 on a raw socket's ring buffer
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * Try to set tpacket_req3.tp_sizeof_priv to a value with the high bit set. So
8f08c3bdfSopenharmony_ci * that tp_block_size < tp_sizeof_priv. If the vulnerability is present then
9f08c3bdfSopenharmony_ci * this will cause an integer arithmetic overflow and the absurd
10f08c3bdfSopenharmony_ci * tp_sizeof_priv value will be allowed. If it has been fixed then setsockopt
11f08c3bdfSopenharmony_ci * will fail with EINVAL.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * We also try a good configuration to make sure it is not failing with EINVAL
14f08c3bdfSopenharmony_ci * for some other reason.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * For a better and more interesting discussion of this CVE see:
17f08c3bdfSopenharmony_ci * https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci#include <errno.h>
21f08c3bdfSopenharmony_ci#include "tst_test.h"
22f08c3bdfSopenharmony_ci#include "tst_safe_net.h"
23f08c3bdfSopenharmony_ci#include "lapi/if_packet.h"
24f08c3bdfSopenharmony_ci#include "lapi/if_ether.h"
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_cistatic int sk;
27f08c3bdfSopenharmony_cistatic long pgsz;
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_cistatic void setup(void)
30f08c3bdfSopenharmony_ci{
31f08c3bdfSopenharmony_ci	pgsz = SAFE_SYSCONF(_SC_PAGESIZE);
32f08c3bdfSopenharmony_ci}
33f08c3bdfSopenharmony_ci
34f08c3bdfSopenharmony_cistatic void cleanup(void)
35f08c3bdfSopenharmony_ci{
36f08c3bdfSopenharmony_ci	if (sk > 0)
37f08c3bdfSopenharmony_ci		SAFE_CLOSE(sk);
38f08c3bdfSopenharmony_ci}
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_cistatic int create_skbuf(unsigned int sizeof_priv)
41f08c3bdfSopenharmony_ci{
42f08c3bdfSopenharmony_ci	int ver = TPACKET_V3;
43f08c3bdfSopenharmony_ci	struct tpacket_req3 req = {};
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci	req.tp_block_size = pgsz;
46f08c3bdfSopenharmony_ci	req.tp_block_nr = 2;
47f08c3bdfSopenharmony_ci	req.tp_frame_size = req.tp_block_size;
48f08c3bdfSopenharmony_ci	req.tp_frame_nr = req.tp_block_nr;
49f08c3bdfSopenharmony_ci	req.tp_retire_blk_tov = 100;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	req.tp_sizeof_priv = sizeof_priv;
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	sk = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
54f08c3bdfSopenharmony_ci	TEST(setsockopt(sk, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver)));
55f08c3bdfSopenharmony_ci	if (TST_RET && TST_ERR == EINVAL)
56f08c3bdfSopenharmony_ci		tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
57f08c3bdfSopenharmony_ci	if (TST_RET)
58f08c3bdfSopenharmony_ci		tst_brk(TBROK | TTERRNO, "setsockopt(sk, SOL_PACKET, PACKET_VERSION, TPACKET_V3)");
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	return setsockopt(sk, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
61f08c3bdfSopenharmony_ci}
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_cistatic void good_size(void)
64f08c3bdfSopenharmony_ci{
65f08c3bdfSopenharmony_ci	TEST(create_skbuf(512));
66f08c3bdfSopenharmony_ci	if (TST_RET)
67f08c3bdfSopenharmony_ci		tst_brk(TBROK | TTERRNO, "Can't create ring buffer with good settings");
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	tst_res(TPASS, "Can create ring buffer with good settinegs");
70f08c3bdfSopenharmony_ci}
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_cistatic void bad_size(void)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	TEST(create_skbuf(3U << 30));
75f08c3bdfSopenharmony_ci	if (TST_RET && TST_ERR != EINVAL)
76f08c3bdfSopenharmony_ci		tst_brk(TBROK | TTERRNO, "Unexpected setsockopt() error");
77f08c3bdfSopenharmony_ci	if (TST_RET)
78f08c3bdfSopenharmony_ci		tst_res(TPASS | TTERRNO, "Refused bad tp_sizeof_priv value");
79f08c3bdfSopenharmony_ci	else
80f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Allowed bad tp_sizeof_priv value");
81f08c3bdfSopenharmony_ci}
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_cistatic void run(unsigned int i)
84f08c3bdfSopenharmony_ci{
85f08c3bdfSopenharmony_ci	if (i == 0)
86f08c3bdfSopenharmony_ci		good_size();
87f08c3bdfSopenharmony_ci	else
88f08c3bdfSopenharmony_ci		bad_size();
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_ci	SAFE_CLOSE(sk);
91f08c3bdfSopenharmony_ci}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_cistatic struct tst_test test = {
94f08c3bdfSopenharmony_ci	.test = run,
95f08c3bdfSopenharmony_ci	.tcnt = 2,
96f08c3bdfSopenharmony_ci	.needs_root = 1,
97f08c3bdfSopenharmony_ci	.setup = setup,
98f08c3bdfSopenharmony_ci	.cleanup = cleanup,
99f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
100f08c3bdfSopenharmony_ci		{"CVE", "2017-7308"},
101f08c3bdfSopenharmony_ci		{}
102f08c3bdfSopenharmony_ci	}
103f08c3bdfSopenharmony_ci};
104