<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Apr 3, 2017 at 4:26 PM, Chad Versace <span dir="ltr"><<a href="mailto:chadversary@chromium.org" target="_blank">chadversary@chromium.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Wed 15 Mar 2017, Jason Ekstrand wrote:<br>
</span><span class="">> This cache allows us to easily ensure that we have a unique anv_bo for<br>
> each gem handle.  We'll need this in order to support multiple-import of<br>
> memory objects and semaphores.<br>
><br>
> v2 (Jason Ekstrand):<br>
>  - Reject BO imports if the size doesn't match the prime fd size as<br>
>    reported by lseek().<br>
><br>
> v3 (Jason Ekstrand):<br>
>  - Fix reference counting around cache_release (Chris Willson)<br>
>  - Move the mutex_unlock() later in cache_release<br>
> ---<br>
>  src/intel/vulkan/anv_<wbr>allocator.c | 261 ++++++++++++++++++++++++++++++<wbr>+++++++++<br>
>  src/intel/vulkan/anv_private.h   |  26 ++++<br>
>  2 files changed, 287 insertions(+)<br>
<br>
<br>
<br>
</span><span class="">> +VkResult<br>
> +anv_bo_cache_import(struct anv_device *device,<br>
> +                    struct anv_bo_cache *cache,<br>
> +                    int fd, uint64_t size, struct anv_bo **bo_out,<br>
> +                    VkAllocationCallbacks *alloc)<br>
> +{<br>
> +   pthread_mutex_lock(&cache-><wbr>mutex);<br>
> +<br>
> +   /* The kernel is going to give us whole pages anyway */<br>
> +   size = align_u64(size, 4096);<br>
> +<br>
> +   uint32_t gem_handle = anv_gem_fd_to_handle(device, fd);<br>
> +   if (!gem_handle) {<br>
> +      pthread_mutex_unlock(&cache-><wbr>mutex);<br>
> +      return vk_error(VK_ERROR_INVALID_<wbr>EXTERNAL_HANDLE_KHX);<br>
> +   }<br>
> +<br>
> +   struct anv_cached_bo *bo = anv_bo_cache_lookup_locked(<wbr>cache, gem_handle);<br>
> +   if (bo) {<br>
> +      assert(bo->bo.size == size);<br>
<br>
</span>For security's sake, we must always check the size, even if the bo is in<br>
the cache. An assertion isn't enough. A malicious client may tell the<br>
truth the first time when sending the fd to the trusted app. The<br>
malicious client may then dup the fd and send it to the trusted app with<br>
a false size.<br></blockquote><div><br></div><div>Yup.  Fixed locally.<br><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
> +      __sync_fetch_and_add(&bo-><wbr>refcount, 1);<br>
> +   } else {<br>
> +      /* For security purposes, we reject BO imports where the size does not<br>
> +       * match exactly.  This prevents a malicious client from passing a<br>
> +       * buffer to a trusted client, lying about the size, and telling the<br>
> +       * trusted client to try and texture from an image that goes<br>
> +       * out-of-bounds.  This sort of thing could lead to GPU hangs or worse<br>
> +       * in the trusted client.  The trusted client can protect itself against<br>
> +       * this sort of attack but only if it can trust the buffer size.<br>
> +       */<br>
<br>
> +      off_t import_size = lseek(fd, 0, SEEK_END);<br>
> +      if (import_size == (off_t)-1 || import_size != size) {<br>
> +         anv_gem_close(device, gem_handle);<br>
> +         pthread_mutex_unlock(&cache-><wbr>mutex);<br>
> +         return vk_error(VK_ERROR_INVALID_<wbr>EXTERNAL_HANDLE_KHX);<br>
> +      }<br>
> +<br>
> +      struct anv_cached_bo *bo =<br>
> +         vk_alloc(alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_<wbr>OBJECT);<br>
> +      if (!bo) {<br>
> +         anv_gem_close(device, gem_handle);<br>
> +         pthread_mutex_unlock(&cache-><wbr>mutex);<br>
> +         return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
> +      }<br>
> +<br>
> +      bo->refcount = 1;<br>
> +<br>
> +      anv_bo_init(&bo->bo, gem_handle, size);<br>
> +<br>
> +      _mesa_hash_table_insert(cache-<wbr>>bo_map, (void *)(uintptr_t)gem_handle, bo);<br>
> +   }<br>
> +<br>
> +   pthread_mutex_unlock(&cache-><wbr>mutex);<br>
> +<br>
> +   /* From the Vulkan spec:<br>
> +    *<br>
> +    *    "Importing memory from a file descriptor transfers ownership of<br>
> +    *    the file descriptor from the application to the Vulkan<br>
> +    *    implementation. The application must not perform any operations on<br>
> +    *    the file descriptor after a successful import."<br>
> +    *<br>
> +    * If the import fails, we leave the file descriptor open.<br>
> +    */<br>
> +   close(fd);<br>
> +<br>
> +   *bo_out = &bo->bo;<br>
> +<br>
> +   return VK_SUCCESS;<br>
> +}<br>
</div></div></blockquote></div><br></div></div>