asamy/ksm

Wrong number of MAX_FIXED_MTRR

wbenny opened this issue · 1 comments

Type of this issue (please specify)

  • This is a bug in the upstream tree as-is unmodified.
  • This is a support matter (i.e. your own modified tree)
  • This is a technical question

Issue description

mtrr_ranges array has wrong size and may eventually overflow if user gets really REALLY unlucky

Current Behavior

Let's deconstruct this issue:
in ksm.h:
struct mtrr_range mtrr_ranges[MAX_MTRR];

in mm.h:

#define MAX_VAR_MTRR		255
#define MAX_FIXED_MTRR		11
#define MAX_MTRR		MAX_VAR_MTRR + MAX_FIXED_MTRR

in ksm.c:

	mm_cache_mtrr_ranges(&k->mtrr_ranges[0], &k->mtrr_count, &k->mtrr_def);

in mm.c:

		for (msr = __readmsr(MSR_MTRRfix64K_00000), offset = 0x10000, base = 0;
		     msr != 0; msr >>= 8, base += offset)
			make_mtrr_range(&ranges[idx++], true, msr & 0xff, base, base + 0x10000);

		for (val = MSR_MTRRfix16K_80000, offset = 0x4000; val <= MSR_MTRRfix16K_A0000; ++val)
			for (msr = __readmsr(val), base = 0x80000;
			     msr != 0; msr >>= 8, base += offset)
				make_mtrr_range(&ranges[idx++], true, msr & 0xff, base, base + 0x4000);

		for (val = MSR_MTRRfix4K_C0000, offset = 0x1000; val <= MSR_MTRRfix4K_F8000; ++val)
			for (msr = __readmsr(val), base = 0xC0000;
			     msr != 0; msr >>= 8, base += offset)
				make_mtrr_range(&ranges[idx++], true, msr & 0xff, base, base + 0x1000);

Here's the problem: for each fixed MTRR, there are actually 8 subranges.
Intel manual says:

11.11.2.2 Fixed Range MTRRs
The fixed memory ranges are mapped with 11 fixed-range registers of 64 bits each. Each of these registers is
divided into 8-bit fields that are used to specify the memory type for each of the sub-ranges the register controls:
• Register IA32_MTRR_FIX64K_00000 — Maps the 512-KByte address range from 0H to 7FFFFH. This range
is divided into eight 64-KByte sub-ranges.
• Registers IA32_MTRR_FIX16K_80000 and IA32_MTRR_FIX16K_A0000 — Maps the two 128-KByte
address ranges from 80000H to BFFFFH. This range is divided into sixteen 16-KByte sub-ranges, 8 ranges per
register.
• Registers IA32_MTRR_FIX4K_C0000 through IA32_MTRR_FIX4K_F8000 — Maps eight 32-KByte
address ranges from C0000H to FFFFFH. This range is divided into sixty-four 4-KByte sub-ranges, 8 ranges per
register.

Expected Behavior

I think fix is as simple as defining MAX_FIXED_MTRR to 11*8.

Inline code / patches to be used when reproducing

From 57ad5c11ab9d5d8c353379b21207902c3e47ba4d Mon Sep 17 00:00:00 2001
From: Petr Benes <w.benny@outlook.com>
Date: Tue, 24 Jul 2018 00:43:12 +0200
Subject: [PATCH] fix MAX_FIXED_MTRR definition

---
 mm.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm.h b/mm.h
index 1a79519..d9863a4 100644
--- a/mm.h
+++ b/mm.h
@@ -406,7 +406,7 @@ struct mtrr_range {
 };
 
 #define MAX_VAR_MTRR		255
-#define MAX_FIXED_MTRR		11
+#define MAX_FIXED_MTRR		11*8
 #define MAX_MTRR		MAX_VAR_MTRR + MAX_FIXED_MTRR
 extern void mm_cache_mtrr_ranges(struct mtrr_range *ranges, int *count, u8 *def_type);
 
-- 
2.17.0.windows.1
asamy commented

Thanks, applied.