Skip to contentSkip to conversation

target-i386: Mask NX bit from cpu_get_phys_page_debug result

PATCH Superseded Jan Kiszka 3 participants 6 messages Mar 6, 2012 – Mar 11, 2012

lore
Share & tools
lore

Jan Kiszka

author
#0 lore raw

PATCH 1/1 target-i386: Mask NX bit from cpu_get_phys_page_debug result

This was a long pending bug, now revealed by the assert in phys_page_find that stumbled over the large page index returned by cpu_get_phys_page_debug for NX-marked pages.

---

Was easily triggerable by attaching gdb to the guest and doing some backtraces that reached into stack addresses.

 target-i386/helper.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
target-i386/helper.c +1 -1
index af6bba2..40fe407 100644
@@ -947,7 +947,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     }
 
     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
-    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+    paddr = (pte & TARGET_PAGE_MASK & ~PG_NX_MASK) + page_offset;
     return paddr;
 }
 
Signature · 1 line
1.7.3.4
#1 lore raw
Quoted 18 lines · Jan Kiszka

This was a long pending bug, now revealed by the assert in phys_page_find that stumbled over the large page index returned by cpu_get_phys_page_debug for NX-marked pages.

---

Was easily triggerable by attaching gdb to the guest and doing some backtraces that reached into stack addresses.

 target-i386/helper.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
target-i386/helper.c +0 -0
index af6bba2..40fe407 100644

target-i386/helper.c target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) · line 953

Quoted 8 lines
target-i386/helper.c +1 -1
@@ -947,7 +947,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     }
 
     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
-    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+    paddr = (pte & TARGET_PAGE_MASK & ~PG_NX_MASK) + page_offset;
     return paddr;
 }
 

Should we not, in addition, mask the software available bits (53-62 IIRC)?

Signature · 1 line
error compiling committee.c: too many arguments to function
#2 lore raw
Quoted 7 lines · Avi Kivity
Quoted 7 lines
target-i386/helper.c +0 -0
index af6bba2..40fe407 100644
@@ -947,7 +947,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     }
 
Quoted 9 lines

target-i386/helper.c target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) · line 953

Quoted 6 lines
target-i386/helper.c +1 -1
     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
-    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+    paddr = (pte & TARGET_PAGE_MASK & ~PG_NX_MASK) + page_offset;
     return paddr;
 }
 

Should we not, in addition, mask the software available bits (53-62 IIRC)?

Also intermediate PTEs want this treatment, not just the last one.

Signature · 1 line
error compiling committee.c: too many arguments to function
author
#3 lore raw

PATCH v2 1/1 target-i386: Mask NX bit from cpu_get_phys_page_debug result

This was a long pending bug, now revealed by the assert in phys_page_find that stumbled over the large page index returned by cpu_get_phys_page_debug for NX-marked pages: We need to mask out NX and all user-definable bits 52..62 from PDEs and the final PTE to avoid corrupting physical addresses.

---

Changes in v2 (as suggested by Avi):
- Mask PDEs as well
- Mask user-definable bits

 target-i386/cpu.h    |    1 +
 target-i386/helper.c |   13 +++++++------
 2 files changed, 8 insertions(+), 6 deletions(-)
target-i386/cpu.h +1 -0
index 196b0c5..36e3d29 100644
@@ -241,6 +241,7 @@
 #define PG_DIRTY_MASK	 (1 << PG_DIRTY_BIT)
 #define PG_PSE_MASK	 (1 << PG_PSE_BIT)
 #define PG_GLOBAL_MASK	 (1 << PG_GLOBAL_BIT)
+#define PG_HI_USER_MASK  0x7ff0000000000000LL
 #define PG_NX_MASK	 (1LL << PG_NX_BIT)
 
 #define PG_ERROR_W_BIT     1
target-i386/helper.c +7 -6
index af6bba2..f4f3c27 100644
@@ -885,8 +885,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
             if (!(pml4e & PG_PRESENT_MASK))
                 return -1;
 
-            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
-                env->a20_mask;
+            pdpe_addr = ((pml4e & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
+                         (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask;
             pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK))
                 return -1;
@@ -900,8 +900,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
                 return -1;
         }
 
-        pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
-            env->a20_mask;
+        pde_addr = ((pdpe & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
+                    (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask;
         pde = ldq_phys(pde_addr);
         if (!(pde & PG_PRESENT_MASK)) {
             return -1;
@@ -912,11 +912,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
             pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
         } else {
             /* 4 KB page */
-            pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
-                env->a20_mask;
+            pte_addr = ((pde & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
+                        (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask;
             page_size = 4096;
             pte = ldq_phys(pte_addr);
         }
+        pte &= ~(PG_NX_MASK | PG_HI_USER_MASK);
         if (!(pte & PG_PRESENT_MASK))
             return -1;
     } else {
Signature · 1 line
1.7.3.4
Reviewed-by on v2 1/1
#4 lore raw
Quoted 7 lines · Jan Kiszka

This was a long pending bug, now revealed by the assert in phys_page_find that stumbled over the large page index returned by cpu_get_phys_page_debug for NX-marked pages: We need to mask out NX and all user-definable bits 52..62 from PDEs and the final PTE to avoid corrupting physical addresses.

Signature · 1 line
error compiling committee.c: too many arguments to function
Applied
#5 lore raw
In reply to Jan Kiszka

Thanks, applied.

Quoted 72 lines · Jan Kiszka

This was a long pending bug, now revealed by the assert in phys_page_find that stumbled over the large page index returned by cpu_get_phys_page_debug for NX-marked pages: We need to mask out NX and all user-definable bits 52..62 from PDEs and the final PTE to avoid corrupting physical addresses.

---

Changes in v2 (as suggested by Avi):
 - Mask PDEs as well
 - Mask user-definable bits

 target-i386/cpu.h    |    1 +
 target-i386/helper.c |   13 +++++++------

 2 files changed, 8 insertions(+), 6 deletions(-)
target-i386/cpu.h +1 -0
index 196b0c5..36e3d29 100644
@@ -241,6 +241,7 @@
  #define PG_DIRTY_MASK   (1 << PG_DIRTY_BIT)
  #define PG_PSE_MASK     (1 << PG_PSE_BIT)
  #define PG_GLOBAL_MASK  (1 << PG_GLOBAL_BIT)
+#define PG_HI_USER_MASK  0x7ff0000000000000LL
  #define PG_NX_MASK      (1LL << PG_NX_BIT)
 
  #define PG_ERROR_W_BIT     1
target-i386/helper.c +4 -4
index af6bba2..f4f3c27 100644
@@ -885,8 +885,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
             if (!(pml4e & PG_PRESENT_MASK))
                 return -1;
 
-            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
-                env->a20_mask;
+            pdpe_addr = ((pml4e & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
+                         (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask;
             pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK))
                 return -1;
@@ -900,8 +900,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
                 return -1;
         }
 
-        pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
-            env->a20_mask;
+        pde_addr = ((pdpe & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
+                    (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask;
         pde = ldq_phys(pde_addr);
         if (!(pde & PG_PRESENT_MASK)) {
             return -1;
@@ -912,11 +912,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)

            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ } else {
            /* 4 KB page */
-            pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
-                env->a20_mask;
+            pte_addr = ((pde & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
+                        (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; page_size = 4096;
            pte = ldq_phys(pte_addr);
        }
+        pte &= ~(PG_NX_MASK | PG_HI_USER_MASK);
        if (!(pte & PG_PRESENT_MASK))
            return -1;
    } else {
--
1.7.3.4