mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-06-27 12:05:56 +02:00
[video_core] fix TOCTOU in Vulkan instance extension enumeration (#4072)
So CreateInstance was enumerating instance extensions twice, and that could race if the driver returned a different list the second time. On some AMD iGPU drivers, we could enable an extension from the first list, then fail the second check with VK_ERROR_EXTENSION_NOT_PRESENT. Fix this by enumerating once and passing that same snapshot into RequiredExtensions. Fixes: https://github.com/eden-emulator/Issue-Reports/issues/414 Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4072 Reviewed-by: Lizzie <lizzie@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
parent
78a1cd0533
commit
ef4113aeaa
1 changed files with 20 additions and 10 deletions
|
|
@ -36,8 +36,8 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<const char*> RequiredExtensions(
|
[[nodiscard]] std::vector<const char*> RequiredExtensions(
|
||||||
const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type,
|
const vk::InstanceDispatch& dld, std::vector<VkExtensionProperties> const& properties,
|
||||||
bool enable_validation) {
|
Core::Frontend::WindowSystemType window_type, bool enable_validation) {
|
||||||
std::vector<const char*> extensions;
|
std::vector<const char*> extensions;
|
||||||
extensions.reserve(6);
|
extensions.reserve(6);
|
||||||
switch (window_type) {
|
switch (window_type) {
|
||||||
|
|
@ -74,14 +74,14 @@ namespace {
|
||||||
if (window_type != Core::Frontend::WindowSystemType::Headless) {
|
if (window_type != Core::Frontend::WindowSystemType::Headless) {
|
||||||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
if (auto const properties = vk::EnumerateInstanceExtensionProperties(dld); properties) {
|
// Probe optional extensions against the same snapshot the caller verifies against, so the
|
||||||
|
// check here and the verification in CreateInstance can never disagree (see TOCTOU note below).
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (AreExtensionsSupported(dld, *properties, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}))
|
if (AreExtensionsSupported(dld, properties, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}))
|
||||||
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||||
#endif
|
#endif
|
||||||
if (enable_validation && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
if (enable_validation && AreExtensionsSupported(dld, properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
}
|
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,9 +128,19 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
std::vector<const char*> const extensions = RequiredExtensions(dld, window_type, enable_validation);
|
// Enumerate instance extensions exactly once. RequiredExtensions() used to enumerate a second
|
||||||
|
// time internally; if the driver returned a different set between the two calls (a real TOCTOU
|
||||||
|
// seen on some AMD iGPU drivers), an extension added to the list could be missing from the
|
||||||
|
// verification snapshot, throwing EXTENSION_NOT_PRESENT on an otherwise valid launch. Sharing
|
||||||
|
// one snapshot for both the optional-extension probe and the final check removes that window.
|
||||||
auto const properties = vk::EnumerateInstanceExtensionProperties(dld);
|
auto const properties = vk::EnumerateInstanceExtensionProperties(dld);
|
||||||
if (!properties || !AreExtensionsSupported(dld, *properties, extensions))
|
if (!properties) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to query instance extension properties");
|
||||||
|
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||||
|
}
|
||||||
|
std::vector<const char*> const extensions =
|
||||||
|
RequiredExtensions(dld, *properties, window_type, enable_validation);
|
||||||
|
if (!AreExtensionsSupported(dld, *properties, extensions))
|
||||||
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||||
std::vector<const char*> layers = Layers(enable_validation);
|
std::vector<const char*> layers = Layers(enable_validation);
|
||||||
RemoveUnavailableLayers(dld, layers);
|
RemoveUnavailableLayers(dld, layers);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue