asamy / ksm

A fast, hackable and simple x64 VT-x hypervisor for Windows and Linux. Builtin userspace sandbox and introspection engine.
https://asamy.github.io/ksm/
GNU General Public License v2.0
837 stars 182 forks source link

Wrong number of MAX_FIXED_MTRR #26

Closed wbenny closed 6 years ago

wbenny commented 6 years ago

Type of this issue (please specify)

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 6 years ago

Thanks, applied.