[LTP] [PATCH] syscalls/setsockopt09: Test use-after-free in socket timer

Martin Doucha mdoucha@suse.cz
Fri Mar 11 17:33:06 CET 2022


setsockopt09 may also trigger kernel crash in socket timer. Add git hash
for the timer fix and add taint check to detect this failure variant.

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
 .../kernel/syscalls/setsockopt/setsockopt09.c | 68 ++++++++++++-------
 1 file changed, 44 insertions(+), 24 deletions(-)

diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt09.c b/testcases/kernel/syscalls/setsockopt/setsockopt09.c
index 4b1ce2e92..3047ec0ff 100644
--- a/testcases/kernel/syscalls/setsockopt/setsockopt09.c
+++ b/testcases/kernel/syscalls/setsockopt/setsockopt09.c
@@ -19,6 +19,11 @@
  *
  *  net/packet: rx_owner_map depends on pg_vec
  *
+ *  commit c800aaf8d869f2b9b47b10c5c312fe19f0a94042
+ *  Author: WANG Cong <xiyou.wangcong@gmail.com>
+ *  Date:   Mon Jul 24 10:07:32 2017 -0700
+ *
+ *  packet: fix use-after-free in prb_retire_rx_blk_timer_expired()
  */
 
 #define _GNU_SOURCE
@@ -50,41 +55,55 @@ static void setup(void)
 
 static void run(void)
 {
-	unsigned int version = TPACKET_V3;
+	unsigned int i, version = TPACKET_V3;
 	struct tpacket_req3 req = {
 		.tp_block_size = 4 * pagesize,
-		.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)));
+	for (i = 0; i < 5; i++) {
+		req.tp_block_nr = 256;
+		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 packet 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));
+		SAFE_CLOSE(sock);
 
-	if (TST_RET == -1 && TST_ERR == EINVAL)
-		tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
+		/* Wait for socket timer to expire just in case */
+		usleep(req.tp_retire_blk_tov * 3000);
 
-	if (TST_RET) {
-		tst_brk(TBROK | TTERRNO,
-			"setsockopt(PACKET_VERSION, TPACKET_V3)");
+		if (tst_taint_check()) {
+			tst_res(TFAIL, "Kernel is vulnerable");
+			return;
+		}
 	}
 
-	/* 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));
-	SAFE_CLOSE(sock);
-
 	tst_res(TPASS, "Nothing bad happened, probably");
 }
 
@@ -111,6 +130,7 @@ static struct tst_test test = {
 	},
 	.tags = (const struct tst_tag[]) {
 		{"linux-git", "ec6af094ea28"},
+		{"linux-git", "c800aaf8d869"},
 		{"CVE", "2021-22600"},
 		{}
 	}
-- 
2.35.1



More information about the ltp mailing list