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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).