diff options
| author | Stenzek <stenzek@gmail.com> | 2016-11-13 18:50:10 +1000 |
|---|---|---|
| committer | Stenzek <stenzek@gmail.com> | 2016-11-28 21:21:55 +1000 |
| commit | 8d48319414d7e3f348e4ef38e976121e9a1fce6a (patch) | |
| tree | 3875647817c8ef5e0f8843f02bba13fc1f12e91d /Source/Core/VideoBackends/Vulkan/ObjectCache.cpp | |
| parent | 9604b336c8213c43dff90fab67df8eaa31cdbbb5 (diff) | |
Vulkan: Validate the pipeline cache before using it
This ensures that if a user changes adapters or vendors we're not passing
invalid data to the driver.
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/ObjectCache.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/ObjectCache.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index d7d505b793..761402e478 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -344,6 +344,13 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk) disk_data.clear(); } + if (!disk_data.empty() && !ValidatePipelineCache(disk_data.data(), disk_data.size())) + { + // Don't use this data. In fact, we should delete it to prevent it from being used next time. + File::Delete(m_pipeline_cache_filename); + disk_data.clear(); + } + VkPipelineCacheCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType nullptr, // const void* pNext @@ -369,6 +376,76 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk) return false; } +// Based on Vulkan 1.0 specification, +// Table 9.1. Layout for pipeline cache header version VK_PIPELINE_CACHE_HEADER_VERSION_ONE +// NOTE: This data is assumed to be in little-endian format. +#pragma pack(push, 4) +struct VK_PIPELINE_CACHE_HEADER +{ + u32 header_length; + u32 header_version; + u32 vendor_id; + u32 device_id; + u8 uuid[VK_UUID_SIZE]; +}; +#pragma pack(pop) +// TODO: Remove the #if here when GCC 5 is a minimum build requirement. +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 +static_assert(std::has_trivial_copy_constructor<VK_PIPELINE_CACHE_HEADER>::value, + "VK_PIPELINE_CACHE_HEADER must be trivially copyable"); +#else +static_assert(std::is_trivially_copyable<VK_PIPELINE_CACHE_HEADER>::value, + "VK_PIPELINE_CACHE_HEADER must be trivially copyable"); +#endif + +bool ObjectCache::ValidatePipelineCache(const u8* data, size_t data_length) +{ + if (data_length < sizeof(VK_PIPELINE_CACHE_HEADER)) + { + ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header"); + return false; + } + + VK_PIPELINE_CACHE_HEADER header; + std::memcpy(&header, data, sizeof(header)); + if (header.header_length < sizeof(VK_PIPELINE_CACHE_HEADER)) + { + ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header length"); + return false; + } + + if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) + { + ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header version"); + return false; + } + + if (header.vendor_id != g_vulkan_context->GetDeviceProperties().vendorID) + { + ERROR_LOG(VIDEO, + "Pipeline cache failed validation: Incorrect vendor ID (file: 0x%X, device: 0x%X)", + header.vendor_id, g_vulkan_context->GetDeviceProperties().vendorID); + return false; + } + + if (header.device_id != g_vulkan_context->GetDeviceProperties().deviceID) + { + ERROR_LOG(VIDEO, + "Pipeline cache failed validation: Incorrect device ID (file: 0x%X, device: 0x%X)", + header.device_id, g_vulkan_context->GetDeviceProperties().deviceID); + return false; + } + + if (std::memcmp(header.uuid, g_vulkan_context->GetDeviceProperties().pipelineCacheUUID, + VK_UUID_SIZE) != 0) + { + ERROR_LOG(VIDEO, "Pipeline cache failed validation: Incorrect UUID"); + return false; + } + + return true; +} + void ObjectCache::DestroyPipelineCache() { for (const auto& it : m_pipeline_objects) |
