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

Re: [Xen-devel] [PATCH L1TF MDS GT v1 2/3] common/grant_table: harden bound accesses



>>> On 24.05.19 at 11:54, <nmanthey@xxxxxxxxx> wrote:
> On 5/23/19 16:17, Jan Beulich wrote:
>>>>> On 21.05.19 at 09:45, <nmanthey@xxxxxxxxx> wrote:
>>> Guests can issue grant table operations and provide guest controlled
>>> data to them. This data is used as index for memory loads after bound
>>> checks have been done. To avoid speculative out-of-bound accesses, we
>>> use the array_index_nospec macro where applicable, or the macro
>>> block_speculation. Note, that the block_speculation is always used in
>> s/always/already/ ?
> They both work, but the 'always' underlines that a caller can rely on
> the fact that this will happen on all execution path of that function.
> Hence, I like to stick to 'always' here.

Well, I'm not a native speaker, but to me "always" doesn't express
what you want to express here. What you mean I'd word "... is used
on all paths of ..."

>>> the calls to shared_entry_header and nr_grant_entries, so that no
>>> additional protection is required once these functions have been
>>> called.

As an aside, your use of "in the calls to" looks also misleading to me,
because the fences sit in the functions, not at the call sites.

>>> --- a/xen/common/grant_table.c
>>> +++ b/xen/common/grant_table.c
>>> @@ -988,9 +988,10 @@ map_grant_ref(
>>>          PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref %#x for d%d\n",
>>>                   op->ref, rgt->domain->domain_id);
>>>  
>>> -    act = active_entry_acquire(rgt, op->ref);
>>> +    /* This call also ensures the above check cannot be passed 
>>> speculatively */
>>>      shah = shared_entry_header(rgt, op->ref);
>>>      status = rgt->gt_version == 1 ? &shah->flags : &status_entry(rgt, 
>>> op->ref);
>>> +    act = active_entry_acquire(rgt, op->ref);
>> I know we've been there before, but what guarantees that the
>> compiler won't reload op->ref from memory for either of the
>> latter two accesses? In fact afaict it always will, due to the
>> memory clobber in alternative().
> The compiler can reload op->ref from memory, that is fine here, as the
> bound check happens above, and the shared_entry call comes with an
> lfence() by now, so that we will not continue executing speculatively
> with op->ref being out-of-bounds, independently of whether it's from
> memory or registers.

I don't buy this argumentation: In particular if the cache line got
flushed for whatever reason, the load may take almost arbitrarily
long, opening up a large speculation window again using the
destination register of the load (whatever - not bounds checked -
value that ends up holding).

>>> @@ -3863,6 +3883,9 @@ static int gnttab_get_status_frame_mfn(struct domain 
>>> *d,
>>>              return -EINVAL;
>>>      }
>>>  
>>> +    /* Make sure idx is bounded wrt nr_status_frames */
>>> +    block_speculation();
>>> +
>>>      *mfn = _mfn(virt_to_mfn(gt->status[idx]));
>>>      return 0;
>>>  }
>> Why don't you use array_index_nospec() here? And how come
> There is no specific reason. I will swap.
>> speculation into gnttab_grow_table() is fine a few lines above?
> I do not see a reason why it would be bad to enter that function
> speculatively. There are no accesses that would have to be protected by
> extra checks, afaict. Otherwise, that function should be protected by
> its own.

Which in fact happens, but only in patch 3. This may be worth saying
explicitly here.

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®.