[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xen-users
Subject:    [Xen-users] Xen Security Advisory 282 v1 - guest use of HLE constructs may lock up host
From:       Xen.org security team <security () xen ! org>
Date:       2018-11-06 18:41:04
Message-ID: E1gK6Hg-0002Qd-P3 () xenbits ! xenproject ! org
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

                    Xen Security Advisory XSA-282

             guest use of HLE constructs may lock up host

ISSUE DESCRIPTION
=================

Various Intel CPU models have an erratum listed under the title
"Processor May Hang When Executing Code In an HLE Transaction".  It
describes a potential hang when using instructions with the XACQUIRE
prefix on the host physical memory range covering the first 4 MiB
starting at the 1GiB boundary.

IMPACT
======

A malicious or buggy guest may cause a CPU to hang, resulting in a DoS
(Denial of Service) affecting the entire host.

VULNERABLE SYSTEMS
==================

All Xen versions are affected.

Only Intel based x86 systems are affected.  Please refer to Intel
documentation as to which specific CPU models are affected.

AMD x86 systems as well as Arm ones are not affected.

MITIGATION
==========

There is no known mitigation.  A BIOS update may be available for some
systems, working around the issue at the firmware level.

RESOLUTION
==========

Applying the appropriate pair of attached patches works around this issue
for the CPU models known to be affected at the time of writing.

xsa282-?.patch                              xen-unstable
xsa282-4.11-1.patch + xsa282-2.patch        Xen 4.11.x, Xen 4.10.x
xsa282-4.9-1.patch + xsa282-2.patch         Xen 4.9.x
xsa282-4.9-1.patch + xsa282-4.8-2.patch     Xen 4.8.x, Xen 4.7.x

$ sha256sum xsa282*
6ef64ca920a58ed9185e81fad3dfa9ca5f6316f1e72ddd4f411f3e79eaf79903  xsa282.meta
ad7093e00b3d6650530c95427ef0e68880883f0cec7229b5f41c9e2dc497ffd5  xsa282-1.patch
7ce7fa105026b189500a31bd3978ec0c6fd9d7c95f688463c25ecce76366be35  xsa282-2.patch
fbff734d678700864563f8214361f391c0cbda9b67ed7256535ed3db388c8feb  xsa282-4.8-2.patch
df833cbe9b8798104a65d44b737c46f97399b86b0ffd03c99fda4c8ecf5a353c  xsa282-4.9-1.patch
68eab296a7124662cbe3c6df8835aff9b4a26160fdbe970e206a7a6ef8d27ec7  xsa282-4.11-1.patch
$

NOTE REGARDING LACK OF EMBARGO
==============================

The issue has been documented publicly in Specification Updates for at
least some of the affected processors for quite some time.
-----BEGIN PGP SIGNATURE-----

iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAlvh3+0MHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZ48QIALQ1hLMewraf+URzsd36EUJNPP+1C8Dg35PavdJ1
mrqBljy/bIYCiLvLm1RwinUPL5vrvkB97/6AjmnpZM83AA3/PLTbh3tpP8fiLUcF
YL7wJogvjv51Q3N8mYHjxGGl5YYVdrgxwxbQIuzRnw2gi/ikd0oAoNce/QIF6iFz
P2I8VjKuQZ6qEzdKXTTiPNQQzL+OfVGQ+RcsthQieWce53p+n1pI1QqbPOwdYtca
/cOhP+vGRzh+4QP50JuN5ikdC/C9KpyjEo5mZVlrZQYPIqzI+vomueCJLPGN3cSY
LBcJc/lT/w/LRgygpbUB/OO8RwK5XB9T4Jm/ssXGpCOTs3Y=
=Ipfd
-----END PGP SIGNATURE-----

["xsa282.meta" (application/octet-stream)]
["xsa282-1.patch" (application/octet-stream)]

From: Jan Beulich <jbeulich@suse.com>
Subject: x86: extend get_platform_badpages() interface

Use a structure so along with an address (now frame number) an order can
also be specified.

This is part of XSA-282.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/guest/xen.c
+++ b/xen/arch/x86/guest/xen.c
@@ -40,7 +40,7 @@ bool __read_mostly xen_guest;
 static __read_mostly uint32_t xen_cpuid_base;
 extern char hypercall_page[];
 static struct rangeset *mem;
-static unsigned long __initdata reserved_pages[2];
+static struct platform_bad_page __initdata reserved_pages[2];
 
 DEFINE_PER_CPU(unsigned int, vcpu_id);
 
@@ -326,7 +326,7 @@ void __init hypervisor_fixup_e820(struct
         panic("Unable to get " #p "\n");        \
     mark_pfn_as_ram(e820, pfn);                 \
     ASSERT(i < ARRAY_SIZE(reserved_pages));     \
-    reserved_pages[i++] = pfn << PAGE_SHIFT;    \
+    reserved_pages[i++].mfn = pfn;              \
 })
     MARK_PARAM_RAM(HVM_PARAM_STORE_PFN);
     if ( !pv_console )
@@ -334,7 +334,7 @@ void __init hypervisor_fixup_e820(struct
 #undef MARK_PARAM_RAM
 }
 
-const unsigned long *__init hypervisor_reserved_pages(unsigned int *size)
+const struct platform_bad_page *__init hypervisor_reserved_pages(unsigned int *size)
 {
     ASSERT(xen_guest);
 
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -5843,23 +5843,23 @@ void arch_dump_shared_mem_info(void)
             mem_sharing_get_nr_saved_mfns());
 }
 
-const unsigned long *__init get_platform_badpages(unsigned int *array_size)
+const struct platform_bad_page *__init get_platform_badpages(unsigned int *array_size)
 {
     u32 igd_id;
-    static unsigned long __initdata bad_pages[] = {
-        0x20050000,
-        0x20110000,
-        0x20130000,
-        0x20138000,
-        0x40004000,
+    static const struct platform_bad_page __initconst snb_bad_pages[] = {
+        { .mfn = 0x20050000 >> PAGE_SHIFT },
+        { .mfn = 0x20110000 >> PAGE_SHIFT },
+        { .mfn = 0x20130000 >> PAGE_SHIFT },
+        { .mfn = 0x20138000 >> PAGE_SHIFT },
+        { .mfn = 0x40004000 >> PAGE_SHIFT },
     };
 
-    *array_size = ARRAY_SIZE(bad_pages);
+    *array_size = ARRAY_SIZE(snb_bad_pages);
     igd_id = pci_conf_read32(0, 0, 2, 0, 0);
-    if ( !IS_SNB_GFX(igd_id) )
-        return NULL;
+    if ( IS_SNB_GFX(igd_id) )
+        return snb_bad_pages;
 
-    return bad_pages;
+    return NULL;
 }
 
 void paging_invlpg(struct vcpu *v, unsigned long linear)
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -270,7 +270,7 @@ void __init init_boot_pages(paddr_t ps,
     unsigned long bad_spfn, bad_epfn;
     const char *p;
 #ifdef CONFIG_X86
-    const unsigned long *badpage = NULL;
+    const struct platform_bad_page *badpage;
     unsigned int i, array_size;
 
     BUILD_BUG_ON(8 * sizeof(frame_table->u.free.first_dirty) <
@@ -299,8 +299,8 @@ void __init init_boot_pages(paddr_t ps,
     {
         for ( i = 0; i < array_size; i++ )
         {
-            bootmem_region_zap(*badpage >> PAGE_SHIFT,
-                               (*badpage >> PAGE_SHIFT) + 1);
+            bootmem_region_zap(badpage->mfn,
+                               badpage->mfn + (1U << badpage->order));
             badpage++;
         }
     }
@@ -312,8 +312,8 @@ void __init init_boot_pages(paddr_t ps,
         {
             for ( i = 0; i < array_size; i++ )
             {
-                bootmem_region_zap(*badpage >> PAGE_SHIFT,
-                                   (*badpage >> PAGE_SHIFT) + 1);
+                bootmem_region_zap(badpage->mfn,
+                                   badpage->mfn + (1U << badpage->order));
                 badpage++;
             }
         }
--- a/xen/include/asm-x86/guest/xen.h
+++ b/xen/include/asm-x86/guest/xen.h
@@ -37,7 +37,7 @@ void hypervisor_ap_setup(void);
 int hypervisor_alloc_unused_page(mfn_t *mfn);
 int hypervisor_free_unused_page(mfn_t mfn);
 void hypervisor_fixup_e820(struct e820map *e820);
-const unsigned long *hypervisor_reserved_pages(unsigned int *size);
+const struct platform_bad_page *hypervisor_reserved_pages(unsigned int *size);
 uint32_t hypervisor_cpuid_base(void);
 void hypervisor_resume(void);
 
@@ -65,7 +65,7 @@ static inline void hypervisor_fixup_e820
     ASSERT_UNREACHABLE();
 }
 
-static inline const unsigned long *hypervisor_reserved_pages(unsigned int *size)
+static inline const struct platform_bad_page *hypervisor_reserved_pages(unsigned int *size)
 {
     ASSERT_UNREACHABLE();
     return NULL;
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -341,7 +341,13 @@ void zap_ro_mpt(mfn_t mfn);
 
 bool is_iomem_page(mfn_t mfn);
 
-const unsigned long *get_platform_badpages(unsigned int *array_size);
+struct platform_bad_page {
+    unsigned long mfn;
+    unsigned int order;
+};
+
+const struct platform_bad_page *get_platform_badpages(unsigned int *array_size);
+
 /* Per page locks:
  * page_lock() is used for two purposes: pte serialization, and memory sharing.
  *

["xsa282-2.patch" (application/octet-stream)]

From: Jan Beulich <jbeulich@suse.com>
Subject: x86: work around HLE host lockup erratum

XACQUIRE prefixed accesses to the 4Mb range of memory starting at 1Gb
are liable to lock up the processor. Disallow use of this memory range.

Unfortunately the available Core Gen7 and Gen8 spec updates are pretty
old, so I can only guess that they're similarly affected when Core Gen6
is and the Xeon counterparts are, too.

This is part of XSA-282.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
v2: Don't apply the workaround when running ourselves virtualized.

--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -5853,6 +5853,22 @@ const struct platform_bad_page *__init g
         { .mfn = 0x20138000 >> PAGE_SHIFT },
         { .mfn = 0x40004000 >> PAGE_SHIFT },
     };
+    static const struct platform_bad_page __initconst hle_bad_page = {
+        .mfn = 0x40000000 >> PAGE_SHIFT, .order = 10
+    };
+
+    switch ( cpuid_eax(1) & 0x000f3ff0 )
+    {
+    case 0x000406e0: /* erratum SKL167 */
+    case 0x00050650: /* erratum SKZ63 */
+    case 0x000506e0: /* errata SKL167 / SKW159 */
+    case 0x000806e0: /* erratum KBL??? */
+    case 0x000906e0: /* errata KBL??? / KBW114 / CFW103 */
+        *array_size = (cpuid_eax(0) >= 7 &&
+                       !(cpuid_ecx(1) & cpufeat_mask(X86_FEATURE_HYPERVISOR)) &&
+                       (cpuid_count_ebx(7, 0) & cpufeat_mask(X86_FEATURE_HLE)));
+        return &hle_bad_page;
+    }
 
     *array_size = ARRAY_SIZE(snb_bad_pages);
     igd_id = pci_conf_read32(0, 0, 2, 0, 0);

["xsa282-4.8-2.patch" (application/octet-stream)]

From: Jan Beulich <jbeulich@suse.com>
Subject: x86: work around HLE host lockup erratum

XACQUIRE prefixed accesses to the 4Mb range of memory starting at 1Gb
are liable to lock up the processor. Disallow use of this memory range.

Unfortunately the available Core Gen7 and Gen8 spec updates are pretty
old, so I can only guess that they're similarly affected when Core Gen6
is and the Xeon counterparts are, too.

This is part of XSA-282.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -6989,6 +6989,25 @@ const struct platform_bad_page *__init g
         { .mfn = 0x20138000 >> PAGE_SHIFT },
         { .mfn = 0x40004000 >> PAGE_SHIFT },
     };
+    static const struct platform_bad_page __initconst hle_bad_page = {
+        .mfn = 0x40000000 >> PAGE_SHIFT, .order = 10
+    };
+
+    switch ( cpuid_eax(1) & 0x000f3ff0 )
+    {
+        unsigned int ebx, dummy;
+
+    case 0x000406e0: /* erratum SKL167 */
+    case 0x00050650: /* erratum SKZ63 */
+    case 0x000506e0: /* errata SKL167 / SKW159 */
+    case 0x000806e0: /* erratum KBL??? */
+    case 0x000906e0: /* errata KBL??? / KBW114 / CFW103 */
+        *array_size = (cpuid_eax(0) >= 7 &&
+                       !(cpuid_ecx(1) & cpufeat_mask(X86_FEATURE_HYPERVISOR)) &&
+                       (cpuid_count(7, 0, &dummy, &ebx, &dummy, &dummy),
+                        ebx & cpufeat_mask(X86_FEATURE_HLE)));
+        return &hle_bad_page;
+    }
 
     *array_size = ARRAY_SIZE(snb_bad_pages);
     igd_id = pci_conf_read32(0, 0, 2, 0, 0);

["xsa282-4.9-1.patch" (application/octet-stream)]

From: Jan Beulich <jbeulich@suse.com>
Subject: x86: extend get_platform_badpages() interface

Use a structure so along with an address (now frame number) an order can
also be specified.

This is part of XSA-282.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -7111,23 +7111,23 @@ void arch_dump_shared_mem_info(void)
             mem_sharing_get_nr_saved_mfns());
 }
 
-const unsigned long *__init get_platform_badpages(unsigned int *array_size)
+const struct platform_bad_page *__init get_platform_badpages(unsigned int *array_size)
 {
     u32 igd_id;
-    static unsigned long __initdata bad_pages[] = {
-        0x20050000,
-        0x20110000,
-        0x20130000,
-        0x20138000,
-        0x40004000,
+    static const struct platform_bad_page __initconst snb_bad_pages[] = {
+        { .mfn = 0x20050000 >> PAGE_SHIFT },
+        { .mfn = 0x20110000 >> PAGE_SHIFT },
+        { .mfn = 0x20130000 >> PAGE_SHIFT },
+        { .mfn = 0x20138000 >> PAGE_SHIFT },
+        { .mfn = 0x40004000 >> PAGE_SHIFT },
     };
 
-    *array_size = ARRAY_SIZE(bad_pages);
+    *array_size = ARRAY_SIZE(snb_bad_pages);
     igd_id = pci_conf_read32(0, 0, 2, 0, 0);
-    if ( !IS_SNB_GFX(igd_id) )
-        return NULL;
+    if ( IS_SNB_GFX(igd_id) )
+        return snb_bad_pages;
 
-    return bad_pages;
+    return NULL;
 }
 
 void paging_invlpg(struct vcpu *v, unsigned long va)
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -270,7 +270,7 @@ void __init init_boot_pages(paddr_t ps,
     unsigned long bad_spfn, bad_epfn;
     const char *p;
 #ifdef CONFIG_X86
-    const unsigned long *badpage = NULL;
+    const struct platform_bad_page *badpage;
     unsigned int i, array_size;
 #endif
 
@@ -295,8 +295,8 @@ void __init init_boot_pages(paddr_t ps,
     {
         for ( i = 0; i < array_size; i++ )
         {
-            bootmem_region_zap(*badpage >> PAGE_SHIFT,
-                               (*badpage >> PAGE_SHIFT) + 1);
+            bootmem_region_zap(badpage->mfn,
+                               badpage->mfn + (1U << badpage->order));
             badpage++;
         }
     }
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -350,7 +350,13 @@ bool is_iomem_page(mfn_t mfn);
 
 void clear_superpage_mark(struct page_info *page);
 
-const unsigned long *get_platform_badpages(unsigned int *array_size);
+struct platform_bad_page {
+    unsigned long mfn;
+    unsigned int order;
+};
+
+const struct platform_bad_page *get_platform_badpages(unsigned int *array_size);
+
 /* Per page locks:
  * page_lock() is used for two purposes: pte serialization, and memory sharing.
  *

["xsa282-4.11-1.patch" (application/octet-stream)]

From: Jan Beulich <jbeulich@suse.com>
Subject: x86: extend get_platform_badpages() interface

Use a structure so along with an address (now frame number) an order can
also be specified.

This is part of XSA-282.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/guest/xen.c
+++ b/xen/arch/x86/guest/xen.c
@@ -40,7 +40,7 @@ bool __read_mostly xen_guest;
 static __read_mostly uint32_t xen_cpuid_base;
 extern char hypercall_page[];
 static struct rangeset *mem;
-static unsigned long __initdata reserved_pages[2];
+static struct platform_bad_page __initdata reserved_pages[2];
 
 DEFINE_PER_CPU(unsigned int, vcpu_id);
 
@@ -326,7 +326,7 @@ void __init hypervisor_fixup_e820(struct
         panic("Unable to get " #p);             \
     mark_pfn_as_ram(e820, pfn);                 \
     ASSERT(i < ARRAY_SIZE(reserved_pages));     \
-    reserved_pages[i++] = pfn << PAGE_SHIFT;    \
+    reserved_pages[i++].mfn = pfn;              \
 })
     MARK_PARAM_RAM(HVM_PARAM_STORE_PFN);
     if ( !pv_console )
@@ -334,7 +334,7 @@ void __init hypervisor_fixup_e820(struct
 #undef MARK_PARAM_RAM
 }
 
-const unsigned long *__init hypervisor_reserved_pages(unsigned int *size)
+const struct platform_bad_page *__init hypervisor_reserved_pages(unsigned int *size)
 {
     ASSERT(xen_guest);
 
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -5768,23 +5768,23 @@ void arch_dump_shared_mem_info(void)
             mem_sharing_get_nr_saved_mfns());
 }
 
-const unsigned long *__init get_platform_badpages(unsigned int *array_size)
+const struct platform_bad_page *__init get_platform_badpages(unsigned int *array_size)
 {
     u32 igd_id;
-    static unsigned long __initdata bad_pages[] = {
-        0x20050000,
-        0x20110000,
-        0x20130000,
-        0x20138000,
-        0x40004000,
+    static const struct platform_bad_page __initconst snb_bad_pages[] = {
+        { .mfn = 0x20050000 >> PAGE_SHIFT },
+        { .mfn = 0x20110000 >> PAGE_SHIFT },
+        { .mfn = 0x20130000 >> PAGE_SHIFT },
+        { .mfn = 0x20138000 >> PAGE_SHIFT },
+        { .mfn = 0x40004000 >> PAGE_SHIFT },
     };
 
-    *array_size = ARRAY_SIZE(bad_pages);
+    *array_size = ARRAY_SIZE(snb_bad_pages);
     igd_id = pci_conf_read32(0, 0, 2, 0, 0);
-    if ( !IS_SNB_GFX(igd_id) )
-        return NULL;
+    if ( IS_SNB_GFX(igd_id) )
+        return snb_bad_pages;
 
-    return bad_pages;
+    return NULL;
 }
 
 void paging_invlpg(struct vcpu *v, unsigned long va)
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -270,7 +270,7 @@ void __init init_boot_pages(paddr_t ps,
     unsigned long bad_spfn, bad_epfn;
     const char *p;
 #ifdef CONFIG_X86
-    const unsigned long *badpage = NULL;
+    const struct platform_bad_page *badpage;
     unsigned int i, array_size;
 
     BUILD_BUG_ON(8 * sizeof(frame_table->u.free.first_dirty) <
@@ -299,8 +299,8 @@ void __init init_boot_pages(paddr_t ps,
     {
         for ( i = 0; i < array_size; i++ )
         {
-            bootmem_region_zap(*badpage >> PAGE_SHIFT,
-                               (*badpage >> PAGE_SHIFT) + 1);
+            bootmem_region_zap(badpage->mfn,
+                               badpage->mfn + (1U << badpage->order));
             badpage++;
         }
     }
@@ -312,8 +312,8 @@ void __init init_boot_pages(paddr_t ps,
         {
             for ( i = 0; i < array_size; i++ )
             {
-                bootmem_region_zap(*badpage >> PAGE_SHIFT,
-                                   (*badpage >> PAGE_SHIFT) + 1);
+                bootmem_region_zap(badpage->mfn,
+                                   badpage->mfn + (1U << badpage->order));
                 badpage++;
             }
         }
--- a/xen/include/asm-x86/guest/xen.h
+++ b/xen/include/asm-x86/guest/xen.h
@@ -37,7 +37,7 @@ void hypervisor_ap_setup(void);
 int hypervisor_alloc_unused_page(mfn_t *mfn);
 int hypervisor_free_unused_page(mfn_t mfn);
 void hypervisor_fixup_e820(struct e820map *e820);
-const unsigned long *hypervisor_reserved_pages(unsigned int *size);
+const struct platform_bad_page *hypervisor_reserved_pages(unsigned int *size);
 uint32_t hypervisor_cpuid_base(void);
 void hypervisor_resume(void);
 
@@ -65,7 +65,7 @@ static inline void hypervisor_fixup_e820
     ASSERT_UNREACHABLE();
 }
 
-static inline const unsigned long *hypervisor_reserved_pages(unsigned int *size)
+static inline const struct platform_bad_page *hypervisor_reserved_pages(unsigned int *size)
 {
     ASSERT_UNREACHABLE();
     return NULL;
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -348,7 +348,13 @@ void zap_ro_mpt(mfn_t mfn);
 
 bool is_iomem_page(mfn_t mfn);
 
-const unsigned long *get_platform_badpages(unsigned int *array_size);
+struct platform_bad_page {
+    unsigned long mfn;
+    unsigned int order;
+};
+
+const struct platform_bad_page *get_platform_badpages(unsigned int *array_size);
+
 /* Per page locks:
  * page_lock() is used for two purposes: pte serialization, and memory sharing.
  *

[Attachment #9 (text/plain)]

_______________________________________________
Xen-users mailing list
Xen-users@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-users

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic