Hi Alexei, On Thu, Jan 04, 2018 at 08:28:11PM -0800, Alexei Starovoitov wrote: > From: Alexei Starovoitov <a...@kernel.org> > > Under speculation, CPUs may mis-predict branches in bounds checks. Thus, > memory accesses under a bounds check may be speculated even if the > bounds check fails, providing a primitive for building a side channel. > > To avoid leaking kernel data round up array-based maps and mask the index > after bounds check, so speculated load with out of bounds index will load > either valid value from the array or zero from the padded area.
Thanks for putting this together, this certainly looks neat. I'm a little worried that in the presence of some CPU/compiler optimisations, the masking may effectively be skipped under speculation. So I'm not sure how robust this is going to be. More on that below. > To avoid duplicating map_lookup functions for root/unpriv always generate > a sequence of bpf instructions equivalent to map_lookup function for > array and array_of_maps map types when map was created by unpriv user. > And unconditionally mask index for percpu_array, since it's fast enough, > even when max_entries are not rounded to power of 2 for root user, > since percpu_array doesn't have map_gen_lookup callback yet. Is there a noticeable slowdown from the masking? Can't we always have that in place? > @@ -157,7 +175,7 @@ static void *percpu_array_map_lookup_elem(struct bpf_map > *map, void *key) > if (unlikely(index >= array->map.max_entries)) > return NULL; > > - return this_cpu_ptr(array->pptrs[index]); > + return this_cpu_ptr(array->pptrs[index & array->index_mask]); As above, I think this isn't necessarily robust, as CPU/compiler optimisations can break the dependency on the index_mask, allowing speculation without a mask. e.g. a compiler could re-write this as: if (array->index_mask != 0xffffffff) index &= array->index_mask; return this_cpu_ptr(array->pptrs[index]); ... which would allow an unmasked index to be used in speculated paths. Similar cases could occur with some CPU implementations. For example, HW value-prediction could result in the use of an all-ones mask under speculation. I think that we may need to be able to provide an arch-specific pointer sanitization sequence (though we could certainly have masking as the default). I have a rough idea as to how that could be plumbed into the JIT. First I need to verify the sequence I have in mind for arm/arm64 is sufficient. Thanks, Mark.