[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH] x86/xpti: Hide almost all of .text and all .data/.rodata/.bss mappings



>>> On 14.02.18 at 17:23, <andrew.cooper3@xxxxxxxxxx> wrote:
> The current XPTI implementation isolates the directmap (and therefore a lot 
> of
> guest data), but a large quantity of CPU0's state (including its stack)
> remains visible.
> 
> Furthermore, an attacker able to read .text is in a vastly superior position
> to normal when it comes to fingerprinting Xen for known vulnerabilities, or
> scanning for ROP/Spectre gadgets.
> 
> Collect together the entrypoints in .text.entry (currently 3x4k frames, but
> can almost certainly be slimmed down), and create a common mapping which is
> inserted into each per-cpu shadow.  The stubs are also inserted into this
> mapping by pointing at the in-use L2.  This allows stubs allocated later (SMP
> boot, or CPU hotplug) to work without further changes to the common 
> mappings.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---
> CC: Jan Beulich <JBeulich@xxxxxxxx>
> CC: Wei Liu <wei.liu2@xxxxxxxxxx>
> CC: Juergen Gross <jgross@xxxxxxxx>
> 
> v2:
>  * Drop "incomplete" warning from the docs.  This is about as complete as it
>    can reasonably get.
>  * Correct BUILD_BUG_ON() calculation, duplicate in the common_pgt code
>  * scope/const improvements
>  * Use .push/.popsection in preference to .previous
>  * Exclude {compat_}create_bounce_frame from .text.entry
>  * Extend the sanity checking of linear in clone_mapping().  There is a 
> latent
>    bug where a bad linear parameter would cause Xen to fall over a NULL 
> pointer.
> ---
>  docs/misc/xen-command-line.markdown |  3 --
>  xen/arch/x86/smpboot.c              | 56 
> +++++++++++++++++++++++++++++++++----
>  xen/arch/x86/x86_64/compat/entry.S  |  5 ++++
>  xen/arch/x86/x86_64/entry.S         | 11 ++++++--
>  xen/arch/x86/xen.lds.S              |  7 +++++
>  5 files changed, 71 insertions(+), 11 deletions(-)
> 
> diff --git a/docs/misc/xen-command-line.markdown 
> b/docs/misc/xen-command-line.markdown
> index 79feba6..8317639 100644
> --- a/docs/misc/xen-command-line.markdown
> +++ b/docs/misc/xen-command-line.markdown
> @@ -1935,9 +1935,6 @@ mode.
>  Override default selection of whether to isolate 64-bit PV guest page
>  tables.
>  
> -** WARNING: Not yet a complete isolation implementation, but better than
> -nothing. **
> -
>  ### xsave
>  > `= <boolean>`
>  
> diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
> index 2ebef03..10bf2f3 100644
> --- a/xen/arch/x86/smpboot.c
> +++ b/xen/arch/x86/smpboot.c
> @@ -622,6 +622,9 @@ unsigned long alloc_stub_page(unsigned int cpu, unsigned 
> long *mfn)
>          unmap_domain_page(memset(__map_domain_page(pg), 0xcc, PAGE_SIZE));
>      }
>  
> +    /* Confirm that all stubs fit in a single L2 pagetable. */
> +    BUILD_BUG_ON(NR_CPUS * PAGE_SIZE > (1u << L3_PAGETABLE_SHIFT));

It's a little confusing that the comment talks about L2 yet the check
is on L3. May I suggest you either use
L2_PAGETABLE_ENTRIES << L2_PAGETABLE_SHIFT or say "are
covered by a single L3 entry" in the comment?

> @@ -646,13 +649,23 @@ static int clone_mapping(const void *ptr, 
> root_pgentry_t *rpt)
>  {
>      unsigned long linear = (unsigned long)ptr, pfn;
>      unsigned int flags;
> -    l3_pgentry_t *pl3e = 
> l4e_to_l3e(idle_pg_table[root_table_offset(linear)]) +
> -                         l3_table_offset(linear);
> +    l3_pgentry_t *pl3e;
>      l2_pgentry_t *pl2e;
>      l1_pgentry_t *pl1e;
>  
> -    if ( linear < DIRECTMAP_VIRT_START )
> -        return 0;
> +    /*
> +     * Sanity check 'linear'.  We only allow cloning from the Xen virtual
> +     * range, and in particular, only from the directmap and .text ranges.
> +     */
> +    if ( root_table_offset(linear) > ROOT_PAGETABLE_LAST_XEN_SLOT ||
> +         root_table_offset(linear) < ROOT_PAGETABLE_FIRST_XEN_SLOT )
> +        return -EINVAL;
> +    if ( !(linear >= DIRECTMAP_VIRT_START ||
> +           (linear >= XEN_VIRT_START && linear < XEN_VIRT_END)) )

Putting it this way is certainly fine, but generally I find using !() on
logical || or && expressions less easy to understand than pushing the
negation through the entire expression. Once having done so, it
might even be debatable whether

    if ( linear < XEN_VIRT_START ||
         (linear >= XEN_VIRT_END && linear < DIRECTMAP_VIRT_START)) )
        return -EINVAL;

wouldn't be better.

With at least the first (comment vs code) aspect taken care of in
both instances
Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>

Jan

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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.