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

Re: [PATCH 02/10] x86: split populating of struct vcpu_time_info into a separate function


  • To: Jan Beulich <jbeulich@xxxxxxxx>, "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Andrew Cooper <Andrew.Cooper3@xxxxxxxxxx>
  • Date: Tue, 17 Jan 2023 20:19:04 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=jFAI3Ux6qPtissa7plSCh2AfaIBdW9fgTpRfbLWjBIc=; b=LN6Wm8Ykc9VcCoif1agvb1/vTQ+rQmkSj3kPIqvz4RYEnY8CQky8J8qEUzMMUO1OIerZMPqczvdsWkNqKjCT1Ql6pXsgTF6NassUvcpKhef5vFQSJe5Wins5KcwI+tGg6xEuZc2ck5ciS6e04uJkWlVKt10UbhutPpX44pABTTTgJ5RPYywwYbMr/bJQgDBhmpWlOaESPiGL524x6ANHbhEknGELgKXcMaqR2s6x12msJCDHhL48HFT8X4wcGvFS6Qi2XbgKOuOVndqsBaMlIOIDcJJFeKOQ3r0y1jVhQ73eQCAXiY1amkJf3bok1dAmg1ITIN+mz3cXHr3fi00UCw==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=XOTfZzPwLZG5YoWQ2I/SrXPQMVAS2SPALjIs1+cl2im67eOCC8t2+JhDbz6l66LBJGBpUiBBfiLsY/FW2kx985pgrGXHSDyaNftL7r7g8BnCubf6dx19/M29Tj0vwzFAjCBTx95VjL3oHl6PECB3E/BSmS8yLs+vDPLwiiU9R/xzrnxMCoXFjE3RsbN66ZKwUjIZLTrMup6+4VgMYRxxwMPg/oe3IidOr2MHwAbgZZwnl0XHXFxRj0Y/1xkQMCqCJCNYhHbjs/wYbzvN+dgd7Xk4PaZmqxVqIcUQNE7BYXYgQXL40C0nogtEbKC+4vfT8SsvOPfGKFRqks2wdkmfcQ==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: George Dunlap <George.Dunlap@xxxxxxxxxx>, Wei Liu <wl@xxxxxxx>, Roger Pau Monne <roger.pau@xxxxxxxxxx>
  • Delivery-date: Tue, 17 Jan 2023 20:19:37 +0000
  • Ironport-data: A9a23:2u388KAujNF1fxVW/wriw5YqxClBgxIJ4kV8jS/XYbTApGtxhTYGz DcZW22OO/2MN2H9e4sna4Sw9UtQ68TVn4U3QQY4rX1jcSlH+JHPbTi7wuUcHAvJd5GeExg3h yk6QoOdRCzhZiaE/n9BCpC48T8nk/nNHuCnYAL9EngZbRd+Tys8gg5Ulec8g4p56fC0GArIs t7pyyHlEAbNNwVcbyRFtMpvlDs15K6p4GpB4QRkDRx2lAS2e0c9Xcp3yZ6ZdxMUcqEMdsamS uDKyq2O/2+x13/B3fv8z94X2mVTKlLjFVDmZkh+AsBOsTAbzsAG6Y4pNeJ0VKtio27hc+ada jl6ncfYpQ8BZsUgkQmGOvVSO3kW0aZuoNcrLZUj2CA6IoKvn3bEmp1T4E8K0YIw2bt9BGAQ+ cwiDiEmRwHYreys/rGkY7w57igjBJGD0II3nFhFlWucIdN9BJfJTuPN+MNS2yo2ioZWB/HCa sEFaD1pKhPdfxlIPVRRA5U79AuqriCnL3sE9xTI++xrvQA/zyQouFTpGPPTdsaHWoN+mUGAq 3id12/4HgsbJJqUzj/tHneE17SXxnqnBdt6+LuQ9ORD3mS0nkAvMSYfUVufn8irqUyDYocKQ 6AT0m90xUQoz2SpRNTgWxyzoFafowURHdFXFoUS+AyLj6bZ/QudLmwFVSJaLswrstcsQj4n3 UPPmMnmbRRwtJWFRHTb8a2bxQ5eIgAQJG4GICMBFg0M5oG5pJlp1k6RCNF+DKSyk9v5Xynqx CyHpzQ/gLNVitMX06K8/hbMhDfESoX1czPZLz7/BgqNhj6Vrqb8D2B0wTA3Ncp9Ebs=
  • Ironport-hdrordr: A9a23:4u49Mak1QsUApa6PQYaIFBbSx57pDfLo3DAbv31ZSRFFG/Fw9/ rCoB17726QtN91YhsdcL+7V5VoLUmzyXcX2/hyAV7BZmnbUQKTRekP0WKL+Vbd8kbFh41gPM lbEpSXCLfLfCJHZcSR2njELz73quP3jJxBho3lvghQpRkBUdAF0+/gYDzranGfQmN9dP0EPa vZ3OVrjRy6d08aa8yqb0N1JNQq97Xw5fTbiQdtPW9f1DWz
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHY4438eIfEX/gnK0SRRrhvSEeRJK6jmsaA
  • Thread-topic: [PATCH 02/10] x86: split populating of struct vcpu_time_info into a separate function

On 19/10/2022 8:39 am, Jan Beulich wrote:
> This is to facilitate subsequent re-use of this code.
>
> While doing so add const in a number of places, extending to
> gtime_to_gtsc() and then for symmetry also its inverse function.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

Acked-by: Andrew Cooper <andrew.cooper@xxxxxxxxxx>

> ---
> I was on the edge of also folding the various is_hvm_domain() into a
> function scope boolean, but then wasn't really certain that this
> wouldn't open up undue speculation opportunities.

I can't see anything interesting under here speculation wise. 
Commentary inline.

>
> --- a/xen/arch/x86/include/asm/time.h
> +++ b/xen/arch/x86/include/asm/time.h
> @@ -52,8 +52,8 @@ uint64_t cf_check acpi_pm_tick_to_ns(uin
>  uint64_t tsc_ticks2ns(uint64_t ticks);
>  
>  uint64_t pv_soft_rdtsc(const struct vcpu *v, const struct cpu_user_regs 
> *regs);
> -u64 gtime_to_gtsc(struct domain *d, u64 time);
> -u64 gtsc_to_gtime(struct domain *d, u64 tsc);
> +uint64_t gtime_to_gtsc(const struct domain *d, uint64_t time);
> +uint64_t gtsc_to_gtime(const struct domain *d, uint64_t tsc);
>  
>  int tsc_set_info(struct domain *d, uint32_t tsc_mode, uint64_t elapsed_nsec,
>                   uint32_t gtsc_khz, uint32_t incarnation);
> --- a/xen/arch/x86/time.c
> +++ b/xen/arch/x86/time.c
> @@ -1373,18 +1373,14 @@ uint64_t tsc_ticks2ns(uint64_t ticks)
>      return scale_delta(ticks, &t->tsc_scale);
>  }
>  
> -static void __update_vcpu_system_time(struct vcpu *v, int force)
> +static void collect_time_info(const struct vcpu *v,
> +                              struct vcpu_time_info *u)
>  {
> -    const struct cpu_time *t;
> -    struct vcpu_time_info *u, _u = {};
> -    struct domain *d = v->domain;
> +    const struct cpu_time *t = &this_cpu(cpu_time);
> +    const struct domain *d = v->domain;
>      s_time_t tsc_stamp;
>  
> -    if ( v->vcpu_info == NULL )
> -        return;
> -
> -    t = &this_cpu(cpu_time);
> -    u = &vcpu_info(v, time);
> +    memset(u, 0, sizeof(*u));
>  
>      if ( d->arch.vtsc )
>      {
> @@ -1392,7 +1388,7 @@ static void __update_vcpu_system_time(st
>  
>          if ( is_hvm_domain(d) )
>          {
> -            struct pl_time *pl = v->domain->arch.hvm.pl_time;
> +            const struct pl_time *pl = d->arch.hvm.pl_time;

A PV guest could in in principle use...

>  
>              stime += pl->stime_offset + v->arch.hvm.stime_offset;

... this pl->stime_offset as the second deference of a whatever happens
to sit under d->arch.hvm.pl_time in the pv union.

In the current build of Xen I have to hand, that's
d->arch.pv.mapcache.{epoch,tlbflush_timestamp}, the combination of which
doesn't seem like it can be steered into being a legal pointer into Xen.

>              if ( stime >= 0 )
> @@ -1403,27 +1399,27 @@ static void __update_vcpu_system_time(st
>          else
>              tsc_stamp = gtime_to_gtsc(d, stime);
>  
> -        _u.tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac;
> -        _u.tsc_shift         = d->arch.vtsc_to_ns.shift;
> +        u->tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac;
> +        u->tsc_shift         = d->arch.vtsc_to_ns.shift;
>      }
>      else
>      {
>          if ( is_hvm_domain(d) && hvm_tsc_scaling_supported )

On the other hand, this is isn't safe.  There's no protection of the &&
calculation, but...

>          {
>              tsc_stamp            = hvm_scale_tsc(d, t->stamp.local_tsc);

... this path is the only path subject to speculative type confusion,
and all it does is read d->arch.hvm.tsc_scaling_ratio, so is
appropriately protected in this instance.

Also, all an attacker could do is encode the scaling ratio alongside
t->stamp.local_tsc (unpredictable) in the calculation for the duration
of the speculative window, with no way I can see to dereference the result.


> -            _u.tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac;
> -            _u.tsc_shift         = d->arch.vtsc_to_ns.shift;
> +            u->tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac;
> +            u->tsc_shift         = d->arch.vtsc_to_ns.shift;
>          }
>          else
>          {
>              tsc_stamp            = t->stamp.local_tsc;
> -            _u.tsc_to_system_mul = t->tsc_scale.mul_frac;
> -            _u.tsc_shift         = t->tsc_scale.shift;
> +            u->tsc_to_system_mul = t->tsc_scale.mul_frac;
> +            u->tsc_shift         = t->tsc_scale.shift;
>          }
>      }
>  
> -    _u.tsc_timestamp = tsc_stamp;
> -    _u.system_time   = t->stamp.local_stime;
> +    u->tsc_timestamp = tsc_stamp;
> +    u->system_time   = t->stamp.local_stime;
>  
>      /*
>       * It's expected that domains cope with this bit changing on every
> @@ -1431,10 +1427,21 @@ static void __update_vcpu_system_time(st
>       * or if it further requires monotonicity checks with other vcpus.
>       */
>      if ( clocksource_is_tsc() )
> -        _u.flags |= XEN_PVCLOCK_TSC_STABLE_BIT;
> +        u->flags |= XEN_PVCLOCK_TSC_STABLE_BIT;
>  
>      if ( is_hvm_domain(d) )
> -        _u.tsc_timestamp += v->arch.hvm.cache_tsc_offset;
> +        u->tsc_timestamp += v->arch.hvm.cache_tsc_offset;

This path is subject to type confusion on v->arch.{pv,hvm}, with a PV
guest able to encode the value of v->arch.pv.ctrlreg[5] into the
timestamp.  But again, no way to dereference the result.


I really don't think there's enough flexibility here for even a
perfectly-timed attacker to abuse.

~Andrew

 


Rackspace

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