Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1551446 > unrolled thread

[RFC] x86/mm/KASLR: Remap GDTs at fixed location

Started byThomas Garnier <thgarnie@google.com>
First post2017-01-04 23:20 +0100
Last post2017-01-05 19:30 +0100
Articles 20 on this page of 39 — 7 participants

Back to article view | Back to linux.kernel


Contents

  [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-04 23:20 +0100
    Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-05 09:30 +0100
      Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Arjan van de Ven <arjan@linux.intel.com> - 2017-01-05 16:10 +0100
        Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 17:50 +0100
          Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Arjan van de Ven <arjan@linux.intel.com> - 2017-01-05 20:10 +0100
            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 20:10 +0100
          Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Borislav Petkov <bp@alien8.de> - 2017-01-06 18:50 +0100
            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-06 19:10 +0100
      Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 17:40 +0100
        Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-06 07:40 +0100
    Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 19:20 +0100
      Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@amacapital.net> - 2017-01-05 19:40 +0100
        Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 19:40 +0100
      Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Arjan van de Ven <arjan@linux.intel.com> - 2017-01-05 20:10 +0100
        Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 20:20 +0100
          Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@kernel.org> - 2017-01-05 21:20 +0100
            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 22:10 +0100
              Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@amacapital.net> - 2017-01-05 22:30 +0100
                Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-05 23:00 +0100
                  Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-06 08:00 +0100
                    Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-06 19:10 +0100
                      Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@kernel.org> - 2017-01-06 23:30 +0100
                        Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-07 00:00 +0100
                          Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@kernel.org> - 2017-01-07 00:40 +0100
                            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-07 08:50 +0100
                              Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@amacapital.net> - 2017-01-07 17:00 +0100
                          Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-07 08:40 +0100
                            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@amacapital.net> - 2017-01-07 17:10 +0100
                            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-09 23:40 +0100
                              Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-10 11:30 +0100
                                Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-10 18:20 +0100
            Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Linus Torvalds <torvalds@linux-foundation.org> - 2017-01-06 00:10 +0100
              Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-06 00:30 +0100
              Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@amacapital.net> - 2017-01-06 03:40 +0100
                Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Thomas Garnier <thgarnie@google.com> - 2017-01-06 19:10 +0100
                  Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@kernel.org> - 2017-01-06 23:00 +0100
                    Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-07 08:50 +0100
        Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Ingo Molnar <mingo@kernel.org> - 2017-01-06 07:50 +0100
    Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Andy Lutomirski <luto@amacapital.net> - 2017-01-05 19:30 +0100

Page 1 of 2  [1] 2  Next page →


#1551446 — [RFC] x86/mm/KASLR: Remap GDTs at fixed location

FromThomas Garnier <thgarnie@google.com>
Date2017-01-04 23:20 +0100
Subject[RFC] x86/mm/KASLR: Remap GDTs at fixed location
Message-ID<sW24x-2nH-1@gated-at.bofh.it>
Each processor holds a GDT in its per-cpu structure. The sgdt
instruction gives the base address of the current GDT. This address can
be used to bypass KASLR memory randomization. With another bug, an
attacker could target other per-cpu structures or deduce the base of the
main memory section (PAGE_OFFSET).

In this change, a space is reserved at the end of the memory range
available for KASLR memory randomization. The space is big enough to hold
the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
mapped at specific offset based on the target CPU. Note that if there is
not enough space available, the GDTs are not remapped.

The document was changed to mention GDT remapping for KASLR. This patch
also include dump page tables support.

This patch was tested on multiple hardware configurations and for
hibernation support.

Signed-off-by: Thomas Garnier <thgarnie@google.com>
---
Based on next-20170104
---
 arch/x86/include/asm/kaslr.h  |   4 ++
 arch/x86/kernel/cpu/common.c  |   7 ++-
 arch/x86/mm/dump_pagetables.c |  10 ++++
 arch/x86/mm/kaslr.c           | 107 +++++++++++++++++++++++++++++++++++++++++-
 kernel/cpu.c                  |   3 ++
 kernel/smp.c                  |   1 +
 6 files changed, 130 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h
index 1052a797d71d..babc32803182 100644
--- a/arch/x86/include/asm/kaslr.h
+++ b/arch/x86/include/asm/kaslr.h
@@ -9,8 +9,12 @@ extern unsigned long vmalloc_base;
 extern unsigned long vmemmap_base;
 
 void kernel_randomize_memory(void);
+void kernel_randomize_smp(void);
+void* kaslr_get_gdt_remap(int cpu);
 #else
 static inline void kernel_randomize_memory(void) { }
+static inline void kernel_randomize_smp(void) { }
+static inline void *kaslr_get_gdt_remap(int cpu) { return NULL; }
 #endif /* CONFIG_RANDOMIZE_MEMORY */
 
 #endif
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index dc1697ca5191..2c8a7b4718ea 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -450,8 +450,13 @@ void load_percpu_segment(int cpu)
 void switch_to_new_gdt(int cpu)
 {
 	struct desc_ptr gdt_descr;
+	struct desc_struct *gdt;
 
-	gdt_descr.address = (long)get_cpu_gdt_table(cpu);
+	gdt = kaslr_get_gdt_remap(cpu);
+	if (!gdt)
+		gdt = get_cpu_gdt_table(cpu);
+
+	gdt_descr.address = (long)gdt;
 	gdt_descr.size = GDT_SIZE - 1;
 	load_gdt(&gdt_descr);
 	/* Reload the per-cpu base */
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index ea9c49adaa1f..213fe01f28dc 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -50,6 +50,9 @@ enum address_markers_idx {
 	LOW_KERNEL_NR,
 	VMALLOC_START_NR,
 	VMEMMAP_START_NR,
+# ifdef CONFIG_RANDOMIZE_MEMORY
+	GDT_REMAP_NR,
+# endif
 # ifdef CONFIG_X86_ESPFIX64
 	ESPFIX_START_NR,
 # endif
@@ -75,6 +78,9 @@ static struct addr_marker address_markers[] = {
 	{ 0/* PAGE_OFFSET */,   "Low Kernel Mapping" },
 	{ 0/* VMALLOC_START */, "vmalloc() Area" },
 	{ 0/* VMEMMAP_START */, "Vmemmap" },
+# ifdef CONFIG_RANDOMIZE_MEMORY
+	{ 0, "GDT remapping" },
+# endif
 # ifdef CONFIG_X86_ESPFIX64
 	{ ESPFIX_BASE_ADDR,	"ESPfix Area", 16 },
 # endif
@@ -442,6 +448,10 @@ static int __init pt_dump_init(void)
 	address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET;
 	address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
 	address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START;
+#ifdef CONFIG_RANDOMIZE_MEMORY
+	address_markers[GDT_REMAP_NR].start_address =
+		(unsigned long) kaslr_get_gdt_remap(0);
+#endif
 #endif
 #ifdef CONFIG_X86_32
 	address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c
index 887e57182716..db1bdb75f8af 100644
--- a/arch/x86/mm/kaslr.c
+++ b/arch/x86/mm/kaslr.c
@@ -22,11 +22,13 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/random.h>
+#include <linux/slab.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
 #include <asm/kaslr.h>
+#include <asm/desc.h>
 
 #include "mm_internal.h"
 
@@ -60,6 +62,7 @@ unsigned long vmalloc_base = __VMALLOC_BASE;
 EXPORT_SYMBOL(vmalloc_base);
 unsigned long vmemmap_base = __VMEMMAP_BASE;
 EXPORT_SYMBOL(vmemmap_base);
+unsigned long gdt_tables_base = 0;
 
 /*
  * Memory regions randomized by KASLR (except modules that use a separate logic
@@ -97,7 +100,7 @@ void __init kernel_randomize_memory(void)
 	unsigned long vaddr = vaddr_start;
 	unsigned long rand, memory_tb;
 	struct rnd_state rand_state;
-	unsigned long remain_entropy;
+	unsigned long remain_entropy, gdt_reserved;
 
 	/*
 	 * All these BUILD_BUG_ON checks ensures the memory layout is
@@ -131,6 +134,13 @@ void __init kernel_randomize_memory(void)
 	for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++)
 		remain_entropy -= get_padding(&kaslr_regions[i]);
 
+	/* Reserve space for fixed GDTs, if we have enough available */
+	gdt_reserved = sizeof(struct gdt_page) * max(setup_max_cpus, 1U);
+	if (gdt_reserved < remain_entropy) {
+		gdt_tables_base = vaddr_end - gdt_reserved;
+		remain_entropy -= gdt_reserved;
+	}
+
 	prandom_seed_state(&rand_state, kaslr_get_random_long("Memory"));
 
 	for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) {
@@ -192,3 +202,98 @@ void __meminit init_trampoline(void)
 	set_pgd(&trampoline_pgd_entry,
 		__pgd(_KERNPG_TABLE | __pa(pud_page_tramp)));
 }
+
+/* Hold the remapping of the gdt page for each cpu */
+DEFINE_PER_CPU_PAGE_ALIGNED(struct desc_struct *, gdt_remap);
+
+/* Return the address where the GDT is remapped for this CPU */
+static unsigned long gdt_remap_address(int cpu)
+{
+	return gdt_tables_base + cpu * sizeof(struct gdt_page);
+}
+
+/* Remap the specified gdt table */
+static struct desc_struct *remap_gdt(int cpu)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	struct desc_struct *gdt;
+	unsigned long addr;
+
+	/* GDT table should be only one page */
+	BUILD_BUG_ON(sizeof(struct gdt_page) != PAGE_SIZE);
+
+	/* Keep the original GDT before the allocator is available */
+	if (!slab_is_available())
+		return NULL;
+
+	gdt = get_cpu_gdt_table(cpu);
+	addr = gdt_remap_address(cpu);
+
+	pgd = pgd_offset_k(addr);
+	pud = pud_alloc(&init_mm, pgd, addr);
+	if (WARN_ON(!pud))
+		return NULL;
+	pmd = pmd_alloc(&init_mm, pud, addr);
+	if (WARN_ON(!pmd))
+		return NULL;
+	pte = pte_alloc_kernel(pmd, addr);
+	if (WARN_ON(!pte))
+		return NULL;
+
+	/* If the PTE is already set, something is wrong with the VA ranges */
+	BUG_ON(!pte_none(*pte));
+
+	/* Remap the target GDT and return it */
+	set_pte_at(&init_mm, addr, pte,
+		   pfn_pte(PFN_DOWN(__pa(gdt)), PAGE_KERNEL));
+	gdt = (struct desc_struct *)addr;
+	per_cpu(gdt_remap, cpu) = gdt;
+	return gdt;
+}
+
+/* Check if GDT remapping is enabled */
+static bool kaslr_gdt_remap_enabled(void)
+{
+	return kaslr_memory_enabled() && gdt_tables_base != 0;
+}
+
+/*
+ * The GDT table address is available to user-mode through the sgdt
+ * instruction. This function will return a fixed remapping to load so you
+ * cannot leak the per-cpu structure address.
+ */
+void* kaslr_get_gdt_remap(int cpu)
+{
+	struct desc_struct *gdt_remapping;
+
+	if (!kaslr_gdt_remap_enabled())
+		return NULL;
+
+	gdt_remapping = per_cpu(gdt_remap, cpu);
+	if (!gdt_remapping)
+		gdt_remapping = remap_gdt(cpu);
+
+	return gdt_remapping;
+}
+
+/*
+ * Switch the first processor GDT to the remapping. The GDT is loaded too early
+ * to generate the remapping correctly. This step is done later at boot or
+ * before other processors come back from hibernation.
+ */
+void kernel_randomize_smp(void)
+{
+	struct desc_ptr gdt_descr;
+	struct desc_struct *gdt;
+
+	gdt = kaslr_get_gdt_remap(raw_smp_processor_id());
+	if (WARN_ON(!gdt))
+		return;
+
+	gdt_descr.address = (long)gdt;
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
+}
diff --git a/kernel/cpu.c b/kernel/cpu.c
index f75c4d031eeb..4d6979299b9a 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1040,6 +1040,9 @@ void enable_nonboot_cpus(void)
 {
 	int cpu, error;
 
+	/* Redo KASLR steps for main processor */
+	kernel_randomize_smp();
+
 	/* Allow everyone to use the CPU hotplug again */
 	cpu_maps_update_begin();
 	__cpu_hotplug_enable();
diff --git a/kernel/smp.c b/kernel/smp.c
index 77fcdb9f2775..e1ef8d05e179 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -554,6 +554,7 @@ void __init smp_init(void)
 
 	idle_threads_init();
 	cpuhp_threads_init();
+	kernel_randomize_smp();
 
 	pr_info("Bringing up secondary CPUs ...\n");
 
-- 
2.11.0.390.gc69c2f50cf-goog

[toc] | [next] | [standalone]


#1551742

FromIngo Molnar <mingo@kernel.org>
Date2017-01-05 09:30 +0100
Message-ID<sWbAR-f6-1@gated-at.bofh.it>
In reply to#1551446
* Thomas Garnier <thgarnie@google.com> wrote:

> Each processor holds a GDT in its per-cpu structure. The sgdt
> instruction gives the base address of the current GDT. This address can
> be used to bypass KASLR memory randomization. With another bug, an
> attacker could target other per-cpu structures or deduce the base of the
> main memory section (PAGE_OFFSET).
> 
> In this change, a space is reserved at the end of the memory range
> available for KASLR memory randomization. The space is big enough to hold
> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
> mapped at specific offset based on the target CPU. Note that if there is
> not enough space available, the GDTs are not remapped.
> 
> The document was changed to mention GDT remapping for KASLR. This patch
> also include dump page tables support.
> 
> This patch was tested on multiple hardware configurations and for
> hibernation support.

>  void kernel_randomize_memory(void);
> +void kernel_randomize_smp(void);
> +void* kaslr_get_gdt_remap(int cpu);

Yeah, no fundamental objections from me to the principle, but I get some bad vibes 
from the naming here: seeing that kernel_randomize_smp() actually makes things 
less random.

Also, don't we want to do this unconditionally and not allow remapping failures? 

The GDT is fairly small, plus making the SGDT instruction expose fewer kernel 
internals would be (marginally) useful on non-randomized kernels as well.

It also makes the code more common, more predictable, more debuggable and less 
complex overall - which is pretty valuable in terms of long term security as well.

Thanks,

	Ingo

[toc] | [prev] | [next] | [standalone]


#1552038

FromArjan van de Ven <arjan@linux.intel.com>
Date2017-01-05 16:10 +0100
Message-ID<sWhPY-4HN-23@gated-at.bofh.it>
In reply to#1551742
On 1/5/2017 12:11 AM, Ingo Molnar wrote:
>
> * Thomas Garnier <thgarnie@google.com> wrote:
>
>> Each processor holds a GDT in its per-cpu structure. The sgdt
>> instruction gives the base address of the current GDT. This address can
>> be used to bypass KASLR memory randomization. With another bug, an
>> attacker could target other per-cpu structures or deduce the base of the
>> main memory section (PAGE_OFFSET).
>>
>> In this change, a space is reserved at the end of the memory range
>> available for KASLR memory randomization. The space is big enough to hold
>> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
>> mapped at specific offset based on the target CPU. Note that if there is
>> not enough space available, the GDTs are not remapped.
>>
>> The document was changed to mention GDT remapping for KASLR. This patch
>> also include dump page tables support.
>>
>> This patch was tested on multiple hardware configurations and for
>> hibernation support.
>
>>  void kernel_randomize_memory(void);
>> +void kernel_randomize_smp(void);
>> +void* kaslr_get_gdt_remap(int cpu);
>
> Yeah, no fundamental objections from me to the principle, but I get some bad vibes
> from the naming here: seeing that kernel_randomize_smp() actually makes things
> less random.
>

kernel_unrandomize_smp() ...

one request.. can we make sure this unrandomization is optional?

[toc] | [prev] | [next] | [standalone]


#1552108

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 17:50 +0100
Message-ID<sWjoJ-5yk-9@gated-at.bofh.it>
In reply to#1552038
On Thu, Jan 5, 2017 at 7:08 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
> On 1/5/2017 12:11 AM, Ingo Molnar wrote:
>>
>>
>> * Thomas Garnier <thgarnie@google.com> wrote:
>>
>>> Each processor holds a GDT in its per-cpu structure. The sgdt
>>> instruction gives the base address of the current GDT. This address can
>>> be used to bypass KASLR memory randomization. With another bug, an
>>> attacker could target other per-cpu structures or deduce the base of the
>>> main memory section (PAGE_OFFSET).
>>>
>>> In this change, a space is reserved at the end of the memory range
>>> available for KASLR memory randomization. The space is big enough to hold
>>> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
>>> mapped at specific offset based on the target CPU. Note that if there is
>>> not enough space available, the GDTs are not remapped.
>>>
>>> The document was changed to mention GDT remapping for KASLR. This patch
>>> also include dump page tables support.
>>>
>>> This patch was tested on multiple hardware configurations and for
>>> hibernation support.
>>
>>
>>>  void kernel_randomize_memory(void);
>>> +void kernel_randomize_smp(void);
>>> +void* kaslr_get_gdt_remap(int cpu);
>>
>>
>> Yeah, no fundamental objections from me to the principle, but I get some
>> bad vibes
>> from the naming here: seeing that kernel_randomize_smp() actually makes
>> things
>> less random.
>>
>
> kernel_unrandomize_smp() ...
>

That seems like a better name.

> one request.. can we make sure this unrandomization is optional?
>

Well, it happens only when KASLR memory randomization is enabled. Do
you think it should have a separate config option?

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552238

FromArjan van de Ven <arjan@linux.intel.com>
Date2017-01-05 20:10 +0100
Message-ID<sWlAe-791-9@gated-at.bofh.it>
In reply to#1552108
On 1/5/2017 8:40 AM, Thomas Garnier wrote:
> Well, it happens only when KASLR memory randomization is enabled. Do
> you think it should have a separate config option?

no I would want it a runtime option.... "sgdt from ring 3" is going away
with UMIP (and is already possibly gone in virtual machines, see
https://lwn.net/Articles/694385/) and for those cases it would be a shame
to lose the randomization

[toc] | [prev] | [next] | [standalone]


#1552239

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 20:10 +0100
Message-ID<sWlAe-791-7@gated-at.bofh.it>
In reply to#1552238
On Thu, Jan 5, 2017 at 10:56 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
> On 1/5/2017 8:40 AM, Thomas Garnier wrote:
>>
>> Well, it happens only when KASLR memory randomization is enabled. Do
>> you think it should have a separate config option?
>
>
> no I would want it a runtime option.... "sgdt from ring 3" is going away
> with UMIP (and is already possibly gone in virtual machines, see
> https://lwn.net/Articles/694385/) and for those cases it would be a shame
> to lose the randomization
>

That's correct. When UMIP is enabled, we should disable fixed location
for both GDT and IDT. Glad to do that when UMIP support is added.

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552989

FromBorislav Petkov <bp@alien8.de>
Date2017-01-06 18:50 +0100
Message-ID<sWGOl-5dK-1@gated-at.bofh.it>
In reply to#1552108
On Thu, Jan 05, 2017 at 08:40:29AM -0800, Thomas Garnier wrote:
> > kernel_unrandomize_smp() ...
> >
> 
> That seems like a better name.

Hardly... I'd call it something like kaslr_load_gdt() to actually say
what this function is doing.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

[toc] | [prev] | [next] | [standalone]


#1553003

FromThomas Garnier <thgarnie@google.com>
Date2017-01-06 19:10 +0100
Message-ID<sWH7I-5AS-25@gated-at.bofh.it>
In reply to#1552989
On Fri, Jan 6, 2017 at 9:44 AM, Borislav Petkov <bp@alien8.de> wrote:
> On Thu, Jan 05, 2017 at 08:40:29AM -0800, Thomas Garnier wrote:
>> > kernel_unrandomize_smp() ...
>> >
>>
>> That seems like a better name.
>
> Hardly... I'd call it something like kaslr_load_gdt() to actually say
> what this function is doing.
>

True, it loads it only for the main processor though. I will try a
variant like kaslr_load_main_gdt().

> --
> Regards/Gruss,
>     Boris.
>
> Good mailing practices for 400: avoid top-posting and trim the reply.



-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552099

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 17:40 +0100
Message-ID<sWjf3-5uZ-9@gated-at.bofh.it>
In reply to#1551742
On Thu, Jan 5, 2017 at 12:11 AM, Ingo Molnar <mingo@kernel.org> wrote:
>
> * Thomas Garnier <thgarnie@google.com> wrote:
>
>> Each processor holds a GDT in its per-cpu structure. The sgdt
>> instruction gives the base address of the current GDT. This address can
>> be used to bypass KASLR memory randomization. With another bug, an
>> attacker could target other per-cpu structures or deduce the base of the
>> main memory section (PAGE_OFFSET).
>>
>> In this change, a space is reserved at the end of the memory range
>> available for KASLR memory randomization. The space is big enough to hold
>> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
>> mapped at specific offset based on the target CPU. Note that if there is
>> not enough space available, the GDTs are not remapped.
>>
>> The document was changed to mention GDT remapping for KASLR. This patch
>> also include dump page tables support.
>>
>> This patch was tested on multiple hardware configurations and for
>> hibernation support.
>
>>  void kernel_randomize_memory(void);
>> +void kernel_randomize_smp(void);
>> +void* kaslr_get_gdt_remap(int cpu);
>
> Yeah, no fundamental objections from me to the principle, but I get some bad vibes
> from the naming here: seeing that kernel_randomize_smp() actually makes things
> less random.
>

I agree, I went back and forth on the name. I will change it to
something better.

> Also, don't we want to do this unconditionally and not allow remapping failures?
>
> The GDT is fairly small, plus making the SGDT instruction expose fewer kernel
> internals would be (marginally) useful on non-randomized kernels as well.
>
> It also makes the code more common, more predictable, more debuggable and less
> complex overall - which is pretty valuable in terms of long term security as well.
>

Okay, I will add BUG_ON on failures to remap.

> Thanks,
>
>         Ingo

Ingo: I saw the 5-level page table support being sent through. Do you
want me to wait for it to be -next? (Given it will need to be changed
too).

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552554

FromIngo Molnar <mingo@kernel.org>
Date2017-01-06 07:40 +0100
Message-ID<sWwlX-61H-3@gated-at.bofh.it>
In reply to#1552099
* Thomas Garnier <thgarnie@google.com> wrote:

> > Thanks,
> >
> >         Ingo
> 
> Ingo: I saw the 5-level page table support being sent through. Do you
> want me to wait for it to be -next? (Given it will need to be changed
> too).

Please just base your bits on Linus's latest tree - we'll sort out any
conflicts as/when they happen.

Thanks,

	Ingo

[toc] | [prev] | [next] | [standalone]


#1552195

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 19:20 +0100
Message-ID<sWkNQ-6Cu-7@gated-at.bofh.it>
In reply to#1551446
On Thu, Jan 5, 2017 at 9:51 AM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Wed, Jan 4, 2017 at 2:16 PM, Thomas Garnier <thgarnie@google.com> wrote:
>> Each processor holds a GDT in its per-cpu structure. The sgdt
>> instruction gives the base address of the current GDT. This address can
>> be used to bypass KASLR memory randomization. With another bug, an
>> attacker could target other per-cpu structures or deduce the base of the
>> main memory section (PAGE_OFFSET).
>>
>> In this change, a space is reserved at the end of the memory range
>> available for KASLR memory randomization. The space is big enough to hold
>> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
>> mapped at specific offset based on the target CPU. Note that if there is
>> not enough space available, the GDTs are not remapped.
>
> Can we remap it read-only?  I.e. use PAGE_KERNEL_RO instead of
> PAGE_KERNEL.  After all, the ability to modify the GDT is instant
> root.

That's my goal too. I started by doing a RO remap and got couple
problems with hibernation. I can try again for the next iteration or
delay it for another patch. I also need to look at KVM GDT usage, I am
not familiar with it yet.

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552206

FromAndy Lutomirski <luto@amacapital.net>
Date2017-01-05 19:40 +0100
Message-ID<sWl7c-6J7-25@gated-at.bofh.it>
In reply to#1552195
On Thu, Jan 5, 2017 at 9:54 AM, Thomas Garnier <thgarnie@google.com> wrote:
> On Thu, Jan 5, 2017 at 9:51 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>> On Wed, Jan 4, 2017 at 2:16 PM, Thomas Garnier <thgarnie@google.com> wrote:
>>> Each processor holds a GDT in its per-cpu structure. The sgdt
>>> instruction gives the base address of the current GDT. This address can
>>> be used to bypass KASLR memory randomization. With another bug, an
>>> attacker could target other per-cpu structures or deduce the base of the
>>> main memory section (PAGE_OFFSET).
>>>
>>> In this change, a space is reserved at the end of the memory range
>>> available for KASLR memory randomization. The space is big enough to hold
>>> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
>>> mapped at specific offset based on the target CPU. Note that if there is
>>> not enough space available, the GDTs are not remapped.
>>
>> Can we remap it read-only?  I.e. use PAGE_KERNEL_RO instead of
>> PAGE_KERNEL.  After all, the ability to modify the GDT is instant
>> root.
>
> That's my goal too. I started by doing a RO remap and got couple
> problems with hibernation. I can try again for the next iteration or
> delay it for another patch. I also need to look at KVM GDT usage, I am
> not familiar with it yet.

If you want a small adventure, I think a significant KVM-related
performance improvement is available.  Specifically, on VMX exits, the
GDT limit is hardwired to 0xffff (IIRC -- I could be remembering the
actual vaue wrong).  KVM does LGDT to fix it.

If we actually made the GDT have limit 0xffff (presumably by mapping
the zero page a few times to pad it out without wasting memory), then
we would avoid the LGDT.  LGDT is incredibly slow, so this would be a
big win. Want to see if you can make this work with your patch set?

[toc] | [prev] | [next] | [standalone]


#1552209

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 19:40 +0100
Message-ID<sWl7d-6J7-43@gated-at.bofh.it>
In reply to#1552206
On Thu, Jan 5, 2017 at 10:01 AM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Thu, Jan 5, 2017 at 9:54 AM, Thomas Garnier <thgarnie@google.com> wrote:
>> On Thu, Jan 5, 2017 at 9:51 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>>> On Wed, Jan 4, 2017 at 2:16 PM, Thomas Garnier <thgarnie@google.com> wrote:
>>>> Each processor holds a GDT in its per-cpu structure. The sgdt
>>>> instruction gives the base address of the current GDT. This address can
>>>> be used to bypass KASLR memory randomization. With another bug, an
>>>> attacker could target other per-cpu structures or deduce the base of the
>>>> main memory section (PAGE_OFFSET).
>>>>
>>>> In this change, a space is reserved at the end of the memory range
>>>> available for KASLR memory randomization. The space is big enough to hold
>>>> the maximum number of CPUs (as defined by setup_max_cpus). Each GDT is
>>>> mapped at specific offset based on the target CPU. Note that if there is
>>>> not enough space available, the GDTs are not remapped.
>>>
>>> Can we remap it read-only?  I.e. use PAGE_KERNEL_RO instead of
>>> PAGE_KERNEL.  After all, the ability to modify the GDT is instant
>>> root.
>>
>> That's my goal too. I started by doing a RO remap and got couple
>> problems with hibernation. I can try again for the next iteration or
>> delay it for another patch. I also need to look at KVM GDT usage, I am
>> not familiar with it yet.
>
> If you want a small adventure, I think a significant KVM-related
> performance improvement is available.  Specifically, on VMX exits, the
> GDT limit is hardwired to 0xffff (IIRC -- I could be remembering the
> actual vaue wrong).  KVM does LGDT to fix it.
>
> If we actually made the GDT have limit 0xffff (presumably by mapping
> the zero page a few times to pad it out without wasting memory), then
> we would avoid the LGDT.  LGDT is incredibly slow, so this would be a
> big win. Want to see if you can make this work with your patch set?

I can always take a look. If you have any prototype or more details,
feel free to send it to me on a separate thread.

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552252

FromArjan van de Ven <arjan@linux.intel.com>
Date2017-01-05 20:10 +0100
Message-ID<sWlAe-791-39@gated-at.bofh.it>
In reply to#1552195
On 1/5/2017 9:54 AM, Thomas Garnier wrote:

>
> That's my goal too. I started by doing a RO remap and got couple
> problems with hibernation. I can try again for the next iteration or
> delay it for another patch. I also need to look at KVM GDT usage, I am
> not familiar with it yet.

don't we write to the GDT as part of the TLS segment stuff for glibc ?

[toc] | [prev] | [next] | [standalone]


#1552259

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 20:20 +0100
Message-ID<sWlJT-7ej-21@gated-at.bofh.it>
In reply to#1552252
On Thu, Jan 5, 2017 at 10:58 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
> On 1/5/2017 9:54 AM, Thomas Garnier wrote:
>
>>
>> That's my goal too. I started by doing a RO remap and got couple
>> problems with hibernation. I can try again for the next iteration or
>> delay it for another patch. I also need to look at KVM GDT usage, I am
>> not familiar with it yet.
>
>
> don't we write to the GDT as part of the TLS segment stuff for glibc ?
>

Not sure which glibc feature it is.

In this design, you can write to the GDT per-cpu variable that will
remain read-write. You just need to make the remapping writeable when
we load task registers (ltr) then the processor use the current GDT
address. At least that the case I know, I might find more through
testing.

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552303

FromAndy Lutomirski <luto@kernel.org>
Date2017-01-05 21:20 +0100
Message-ID<sWmFY-7Qg-23@gated-at.bofh.it>
In reply to#1552259
On Thu, Jan 5, 2017 at 11:03 AM, Thomas Garnier <thgarnie@google.com> wrote:
> On Thu, Jan 5, 2017 at 10:58 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
>> On 1/5/2017 9:54 AM, Thomas Garnier wrote:
>>
>>>
>>> That's my goal too. I started by doing a RO remap and got couple
>>> problems with hibernation. I can try again for the next iteration or
>>> delay it for another patch. I also need to look at KVM GDT usage, I am
>>> not familiar with it yet.
>>
>>
>> don't we write to the GDT as part of the TLS segment stuff for glibc ?
>>
>
> Not sure which glibc feature it is.
>
> In this design, you can write to the GDT per-cpu variable that will
> remain read-write. You just need to make the remapping writeable when
> we load task registers (ltr) then the processor use the current GDT
> address. At least that the case I know, I might find more through
> testing.

Hmm.  I bet that if we preset the accessed bits in all the segments
then we don't need it to be writable in general.  But your point about
set_thread_area (TLS) is well taken.  However, I strongly suspect that
we could make set_thread_area unconditionally set the accessed bit and
no one would ever notice.

[toc] | [prev] | [next] | [standalone]


#1552333

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 22:10 +0100
Message-ID<sWnsm-8rY-39@gated-at.bofh.it>
In reply to#1552303
On Thu, Jan 5, 2017 at 12:18 PM, Andy Lutomirski <luto@kernel.org> wrote:
> On Thu, Jan 5, 2017 at 11:03 AM, Thomas Garnier <thgarnie@google.com> wrote:
>> On Thu, Jan 5, 2017 at 10:58 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
>>> On 1/5/2017 9:54 AM, Thomas Garnier wrote:
>>>
>>>>
>>>> That's my goal too. I started by doing a RO remap and got couple
>>>> problems with hibernation. I can try again for the next iteration or
>>>> delay it for another patch. I also need to look at KVM GDT usage, I am
>>>> not familiar with it yet.
>>>
>>>
>>> don't we write to the GDT as part of the TLS segment stuff for glibc ?
>>>
>>
>> Not sure which glibc feature it is.
>>
>> In this design, you can write to the GDT per-cpu variable that will
>> remain read-write. You just need to make the remapping writeable when
>> we load task registers (ltr) then the processor use the current GDT
>> address. At least that the case I know, I might find more through
>> testing.
>
> Hmm.  I bet that if we preset the accessed bits in all the segments
> then we don't need it to be writable in general.  But your point about
> set_thread_area (TLS) is well taken.  However, I strongly suspect that
> we could make set_thread_area unconditionally set the accessed bit and
> no one would ever notice.

Not sure I fully understood and I don't want to miss an important
point. Do you mean making GDT (remapping and per-cpu) read-only and
switch the writeable flag only when we write to the per-cpu entry?

-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552342

FromAndy Lutomirski <luto@amacapital.net>
Date2017-01-05 22:30 +0100
Message-ID<sWnLH-83-15@gated-at.bofh.it>
In reply to#1552333
On Thu, Jan 5, 2017 at 1:08 PM, Thomas Garnier <thgarnie@google.com> wrote:
> On Thu, Jan 5, 2017 at 12:18 PM, Andy Lutomirski <luto@kernel.org> wrote:
>> On Thu, Jan 5, 2017 at 11:03 AM, Thomas Garnier <thgarnie@google.com> wrote:
>>> On Thu, Jan 5, 2017 at 10:58 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
>>>> On 1/5/2017 9:54 AM, Thomas Garnier wrote:
>>>>
>>>>>
>>>>> That's my goal too. I started by doing a RO remap and got couple
>>>>> problems with hibernation. I can try again for the next iteration or
>>>>> delay it for another patch. I also need to look at KVM GDT usage, I am
>>>>> not familiar with it yet.
>>>>
>>>>
>>>> don't we write to the GDT as part of the TLS segment stuff for glibc ?
>>>>
>>>
>>> Not sure which glibc feature it is.
>>>
>>> In this design, you can write to the GDT per-cpu variable that will
>>> remain read-write. You just need to make the remapping writeable when
>>> we load task registers (ltr) then the processor use the current GDT
>>> address. At least that the case I know, I might find more through
>>> testing.
>>
>> Hmm.  I bet that if we preset the accessed bits in all the segments
>> then we don't need it to be writable in general.  But your point about
>> set_thread_area (TLS) is well taken.  However, I strongly suspect that
>> we could make set_thread_area unconditionally set the accessed bit and
>> no one would ever notice.
>
> Not sure I fully understood and I don't want to miss an important
> point. Do you mean making GDT (remapping and per-cpu) read-only and
> switch the writeable flag only when we write to the per-cpu entry?
>

What I mean is: write to the GDT through normal percpu access (or
whatever the normal mapping is) but load a read-only alias into the
GDT register.  As long as nothing ever tries to write through the GDTR
alias, no page faults will be generated.  So we just need to make sure
that nothing ever writes to it through GDTR.  AFAIK the only reason
the CPU ever writes to the address in GDTR is to set an accessed bit.

--Andy

[toc] | [prev] | [next] | [standalone]


#1552356

FromThomas Garnier <thgarnie@google.com>
Date2017-01-05 23:00 +0100
Message-ID<sWoeK-ic-15@gated-at.bofh.it>
In reply to#1552342
On Thu, Jan 5, 2017 at 1:19 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Thu, Jan 5, 2017 at 1:08 PM, Thomas Garnier <thgarnie@google.com> wrote:
>> On Thu, Jan 5, 2017 at 12:18 PM, Andy Lutomirski <luto@kernel.org> wrote:
>>> On Thu, Jan 5, 2017 at 11:03 AM, Thomas Garnier <thgarnie@google.com> wrote:
>>>> On Thu, Jan 5, 2017 at 10:58 AM, Arjan van de Ven <arjan@linux.intel.com> wrote:
>>>>> On 1/5/2017 9:54 AM, Thomas Garnier wrote:
>>>>>
>>>>>>
>>>>>> That's my goal too. I started by doing a RO remap and got couple
>>>>>> problems with hibernation. I can try again for the next iteration or
>>>>>> delay it for another patch. I also need to look at KVM GDT usage, I am
>>>>>> not familiar with it yet.
>>>>>
>>>>>
>>>>> don't we write to the GDT as part of the TLS segment stuff for glibc ?
>>>>>
>>>>
>>>> Not sure which glibc feature it is.
>>>>
>>>> In this design, you can write to the GDT per-cpu variable that will
>>>> remain read-write. You just need to make the remapping writeable when
>>>> we load task registers (ltr) then the processor use the current GDT
>>>> address. At least that the case I know, I might find more through
>>>> testing.
>>>
>>> Hmm.  I bet that if we preset the accessed bits in all the segments
>>> then we don't need it to be writable in general.  But your point about
>>> set_thread_area (TLS) is well taken.  However, I strongly suspect that
>>> we could make set_thread_area unconditionally set the accessed bit and
>>> no one would ever notice.
>>
>> Not sure I fully understood and I don't want to miss an important
>> point. Do you mean making GDT (remapping and per-cpu) read-only and
>> switch the writeable flag only when we write to the per-cpu entry?
>>
>
> What I mean is: write to the GDT through normal percpu access (or
> whatever the normal mapping is) but load a read-only alias into the
> GDT register.  As long as nothing ever tries to write through the GDTR
> alias, no page faults will be generated.  So we just need to make sure
> that nothing ever writes to it through GDTR.  AFAIK the only reason
> the CPU ever writes to the address in GDTR is to set an accessed bit.
>

A write is made when we use load_TR_desc (ltr). I didn't see any other yet.

> --Andy



-- 
Thomas

[toc] | [prev] | [next] | [standalone]


#1552556

FromIngo Molnar <mingo@kernel.org>
Date2017-01-06 08:00 +0100
Message-ID<sWwFj-693-1@gated-at.bofh.it>
In reply to#1552356
* Thomas Garnier <thgarnie@google.com> wrote:

> >> Not sure I fully understood and I don't want to miss an important point. Do 
> >> you mean making GDT (remapping and per-cpu) read-only and switch the 
> >> writeable flag only when we write to the per-cpu entry?
> >
> > What I mean is: write to the GDT through normal percpu access (or whatever the 
> > normal mapping is) but load a read-only alias into the GDT register.  As long 
> > as nothing ever tries to write through the GDTR alias, no page faults will be 
> > generated.  So we just need to make sure that nothing ever writes to it 
> > through GDTR.  AFAIK the only reason the CPU ever writes to the address in 
> > GDTR is to set an accessed bit.
> 
> A write is made when we use load_TR_desc (ltr). I didn't see any other yet.

Is this write to the GDT, generated by the LTR instruction, done unconditionally 
by the hardware?

Thanks,

	Ingo

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web