From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Jan Beulich <JBeulich@suse.com>,
xen-devel <xen-devel@lists.xenproject.org>
Cc: Keir Fraser <keir@xen.org>
Subject: Re: [PATCH 4/4] x86: switch default mapping attributes to non-executable
Date: Tue, 19 May 2015 19:53:58 +0100 [thread overview]
Message-ID: <555B86C6.5060503@citrix.com> (raw)
In-Reply-To: <5559FB96020000780007B1A2@mail.emea.novell.com>
On 18/05/15 13:47, Jan Beulich wrote:
> Only a very limited subset of mappings need to be done as executable
> ones; in particular the direct mapping should not be executable to
> limit the damage attackers can cause by exploiting security relevant
> bugs.
>
> The EFI change at once includes an adjustment to set NX only when
> supported by the hardware.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>
> --- a/xen/arch/x86/domain.c
> +++ b/xen/arch/x86/domain.c
> @@ -293,7 +293,7 @@ struct vcpu_guest_context *alloc_vcpu_gu
> free_vcpu_guest_context(NULL);
> return NULL;
> }
> - __set_fixmap(idx - i, page_to_mfn(pg), __PAGE_HYPERVISOR);
> + __set_fixmap(idx - i, page_to_mfn(pg), __PAGE_HYPERVISOR_RW);
> per_cpu(vgc_pages[i], cpu) = pg;
> }
> return (void *)fix_to_virt(idx);
> --- a/xen/arch/x86/domain_page.c
> +++ b/xen/arch/x86/domain_page.c
> @@ -160,7 +160,7 @@ void *map_domain_page(unsigned long mfn)
>
> spin_unlock(&dcache->lock);
>
> - l1e_write(&MAPCACHE_L1ENT(idx), l1e_from_pfn(mfn, __PAGE_HYPERVISOR));
> + l1e_write(&MAPCACHE_L1ENT(idx), l1e_from_pfn(mfn, __PAGE_HYPERVISOR_RW));
>
> out:
> local_irq_restore(flags);
> --- a/xen/arch/x86/mm.c
> +++ b/xen/arch/x86/mm.c
> @@ -4416,7 +4416,7 @@ long set_gdt(struct vcpu *v,
> for ( i = 0; i < nr_pages; i++ )
> {
> v->arch.pv_vcpu.gdt_frames[i] = frames[i];
> - l1e_write(&pl1e[i], l1e_from_pfn(frames[i], __PAGE_HYPERVISOR));
> + l1e_write(&pl1e[i], l1e_from_pfn(frames[i], __PAGE_HYPERVISOR_RW));
> }
>
> xfree(pfns);
> @@ -6004,7 +6004,7 @@ int create_perdomain_mapping(struct doma
> if ( !IS_NIL(ppg) )
> *ppg++ = pg;
> l1tab[l1_table_offset(va)] =
> - l1e_from_page(pg, __PAGE_HYPERVISOR | _PAGE_AVAIL0);
> + l1e_from_page(pg, __PAGE_HYPERVISOR_RW | _PAGE_AVAIL0);
> l2e_add_flags(*pl2e, _PAGE_AVAIL0);
> }
> else
> @@ -6133,7 +6133,7 @@ void memguard_init(void)
> (unsigned long)__va(start),
> start >> PAGE_SHIFT,
> (__pa(&_end) + PAGE_SIZE - 1 - start) >> PAGE_SHIFT,
> - __PAGE_HYPERVISOR|MAP_SMALL_PAGES);
> + __PAGE_HYPERVISOR_RW|MAP_SMALL_PAGES);
> BUG_ON(start != xen_phys_start);
> map_pages_to_xen(
> XEN_VIRT_START,
> @@ -6146,7 +6146,7 @@ static void __memguard_change_range(void
> {
> unsigned long _p = (unsigned long)p;
> unsigned long _l = (unsigned long)l;
> - unsigned int flags = __PAGE_HYPERVISOR | MAP_SMALL_PAGES;
> + unsigned int flags = __PAGE_HYPERVISOR_RW | MAP_SMALL_PAGES;
>
> /* Ensure we are dealing with a page-aligned whole number of pages. */
> ASSERT((_p&~PAGE_MASK) == 0);
> --- a/xen/arch/x86/setup.c
> +++ b/xen/arch/x86/setup.c
> @@ -900,7 +900,7 @@ void __init noreturn __start_xen(unsigne
> /* The only data mappings to be relocated are in the Xen area. */
> pl2e = __va(__pa(l2_xenmap));
> *pl2e++ = l2e_from_pfn(xen_phys_start >> PAGE_SHIFT,
> - PAGE_HYPERVISOR | _PAGE_PSE);
> + PAGE_HYPERVISOR_RWX | _PAGE_PSE);
> for ( i = 1; i < L2_PAGETABLE_ENTRIES; i++, pl2e++ )
> {
> if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) )
> @@ -1087,7 +1087,7 @@ void __init noreturn __start_xen(unsigne
> /* This range must not be passed to the boot allocator and
> * must also not be mapped with _PAGE_GLOBAL. */
> map_pages_to_xen((unsigned long)__va(map_e), PFN_DOWN(map_e),
> - PFN_DOWN(e - map_e), __PAGE_HYPERVISOR);
> + PFN_DOWN(e - map_e), __PAGE_HYPERVISOR_RW);
> }
> if ( s < map_s )
> {
> --- a/xen/arch/x86/x86_64/mm.c
> +++ b/xen/arch/x86/x86_64/mm.c
> @@ -895,6 +895,33 @@ void __init subarch_init_memory(void)
> share_xen_page_with_privileged_guests(page, XENSHARE_readonly);
> }
> }
> +
> + /* Mark low 16Mb of direct map NX if hardware supports it. */
> + if ( !cpu_has_nx )
> + return;
> +
> + v = DIRECTMAP_VIRT_START + (1UL << 20);
What about 0-1MB ?
> + l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[l3_table_offset(v)];
> + ASSERT(l3e_get_flags(l3e) & _PAGE_PRESENT);
> + do {
> + l2e = l3e_to_l2e(l3e)[l2_table_offset(v)];
> + ASSERT(l2e_get_flags(l2e) & _PAGE_PRESENT);
> + if ( l2e_get_flags(l2e) & _PAGE_PSE )
> + {
> + l2e_add_flags(l2e, _PAGE_NX_BIT);
> + l3e_to_l2e(l3e)[l2_table_offset(v)] = l2e;
> + v += 1 << L2_PAGETABLE_SHIFT;
> + }
> + else
> + {
> + l1_pgentry_t l1e = l2e_to_l1e(l2e)[l1_table_offset(v)];
> +
> + ASSERT(l1e_get_flags(l1e) & _PAGE_PRESENT);
> + l1e_add_flags(l1e, _PAGE_NX_BIT);
> + l2e_to_l1e(l2e)[l1_table_offset(v)] = l1e;
> + v += 1 << L1_PAGETABLE_SHIFT;
> + }
> + } while ( v < DIRECTMAP_VIRT_START + (16UL << 20) );
How about just setting l3e.nx and leaving all lower tables alone?
> }
>
> long subarch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
> @@ -1359,7 +1386,7 @@ int memory_add(unsigned long spfn, unsig
> if ( i < spfn )
> i = spfn;
> ret = map_pages_to_xen((unsigned long)mfn_to_virt(i), i,
> - epfn - i, __PAGE_HYPERVISOR);
> + epfn - i, __PAGE_HYPERVISOR_RW);
> if ( ret )
> return ret;
> }
> --- a/xen/common/efi/boot.c
> +++ b/xen/common/efi/boot.c
> @@ -1162,7 +1162,7 @@ void __init efi_init_memory(void)
> EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
> u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
> unsigned long smfn, emfn;
> - unsigned int prot = PAGE_HYPERVISOR;
> + unsigned int prot = PAGE_HYPERVISOR_RWX;
>
> printk(XENLOG_INFO " %013" PRIx64 "-%013" PRIx64
> " type=%u attr=%016" PRIx64 "\n",
> @@ -1195,7 +1195,7 @@ void __init efi_init_memory(void)
> if ( desc->Attribute & EFI_MEMORY_WP )
> prot &= _PAGE_RW;
> if ( desc->Attribute & EFI_MEMORY_XP )
> - prot |= _PAGE_NX_BIT;
> + prot |= _PAGE_NX;
>
> if ( pfn_to_pdx(emfn - 1) < (DIRECTMAP_SIZE >> PAGE_SHIFT) &&
> !(smfn & pfn_hole_mask) &&
> --- a/xen/include/asm-x86/page.h
> +++ b/xen/include/asm-x86/page.h
> @@ -303,7 +303,8 @@ void paging_init(void);
> #define _PAGE_AVAIL1 _AC(0x400,U)
> #define _PAGE_AVAIL2 _AC(0x800,U)
> #define _PAGE_AVAIL _AC(0xE00,U)
> -#define _PAGE_PSE_PAT _AC(0x1000,U)
> +#define _PAGE_PSE_PAT _AC(0x1000,U)
> +#define _PAGE_NX (cpu_has_nx ? _PAGE_NX_BIT : 0)
> /* non-architectural flags */
> #define _PAGE_PAGED 0x2000U
> #define _PAGE_SHARED 0x4000U
> @@ -320,6 +321,9 @@ void paging_init(void);
> #define _PAGE_GNTTAB 0
> #endif
>
> +#define __PAGE_HYPERVISOR_RO (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NX)
> +#define __PAGE_HYPERVISOR_RW (__PAGE_HYPERVISOR_RO | \
> + _PAGE_DIRTY | _PAGE_RW)
> #define __PAGE_HYPERVISOR_RX (_PAGE_PRESENT | _PAGE_ACCESSED)
> #define __PAGE_HYPERVISOR (__PAGE_HYPERVISOR_RX | \
> _PAGE_DIRTY | _PAGE_RW)
> --- a/xen/include/asm-x86/x86_64/page.h
> +++ b/xen/include/asm-x86/x86_64/page.h
> @@ -147,9 +147,20 @@ typedef l4_pgentry_t root_pgentry_t;
> */
> #define _PAGE_GUEST_KERNEL (1U<<12)
>
> -#define PAGE_HYPERVISOR (__PAGE_HYPERVISOR | _PAGE_GLOBAL)
> +#define PAGE_HYPERVISOR_RO (__PAGE_HYPERVISOR_RO | _PAGE_GLOBAL)
> +#define PAGE_HYPERVISOR_RW (__PAGE_HYPERVISOR_RW | _PAGE_GLOBAL)
> #define PAGE_HYPERVISOR_RX (__PAGE_HYPERVISOR_RX | _PAGE_GLOBAL)
> -#define PAGE_HYPERVISOR_NOCACHE (__PAGE_HYPERVISOR_NOCACHE | _PAGE_GLOBAL)
> +#define PAGE_HYPERVISOR_RWX (__PAGE_HYPERVISOR | _PAGE_GLOBAL)
> +
> +#ifdef __ASSEMBLY__
> +/* Dependency on NX being available can't be expressed. */
> +# define PAGE_HYPERVISOR PAGE_HYPERVISOR_RWX
> +# define PAGE_HYPERVISOR_NOCACHE (__PAGE_HYPERVISOR_NOCACHE | _PAGE_GLOBAL)
> +#else
> +# define PAGE_HYPERVISOR PAGE_HYPERVISOR_RW
> +# define PAGE_HYPERVISOR_NOCACHE (__PAGE_HYPERVISOR_NOCACHE | \
> + _PAGE_GLOBAL | _PAGE_NX)
> +#endif
This patch is clearly an improvement, so my comments can possibly be
deferred to subsequent patches.
After boot, I can't think of a legitimate reason for Xen to have a RWX
mapping. As such, leaving __PAGE_HYPERVISOR around constitutes a risk
that RWX mappings will be used. It would be nice if we could remove all
constants (which aren't BOOT_*) which could lead to accidental use of
RWX mappings on NX-enabled hardware.
I think we also want a warning on boot if we find NX unavailable. The
only 64bit capable CPUs which do not support NX are now 11 years old,
and I don't expect many of those to be running Xen these days. However,
given that "disable NX" is a common BIOS option for compatibility
reasons, we should press people to alter their settings if possible.
~Andrew
>
> #endif /* __X86_64_PAGE_H__ */
>
>
>
next prev parent reply other threads:[~2015-05-19 18:54 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-18 10:28 [PATCH 0/4] x86: don't default to executable mappings Jan Beulich
2015-05-18 12:46 ` [PATCH 1/4] x86: move syscall trampolines off the stack Jan Beulich
2015-05-18 18:39 ` Andrew Cooper
2015-05-19 6:41 ` Jan Beulich
2015-05-19 9:24 ` Andrew Cooper
2015-05-19 16:59 ` Andrew Cooper
2015-05-20 9:16 ` Jan Beulich
2015-05-20 13:37 ` Jan Beulich
2015-05-20 13:58 ` Andrew Cooper
2015-05-20 15:54 ` Jan Beulich
2015-05-18 12:46 ` [PATCH 2/4] x86emul: move stubs " Jan Beulich
2015-05-19 17:33 ` Andrew Cooper
2015-05-20 9:25 ` Jan Beulich
2015-05-18 12:47 ` [PATCH 3/4] x86: move I/O emulation " Jan Beulich
2015-05-19 17:48 ` Andrew Cooper
2015-05-20 13:57 ` Jan Beulich
2015-05-18 12:47 ` [PATCH 4/4] x86: switch default mapping attributes to non-executable Jan Beulich
2015-05-19 18:53 ` Andrew Cooper [this message]
2015-05-20 9:32 ` Jan Beulich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=555B86C6.5060503@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=JBeulich@suse.com \
--cc=keir@xen.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.