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