D3D12: Mitigate the security issue for texture corruption
2D Array texture might corrupt on some devices, making out-of-bound texture access and memory information leak from another texture. This is a critical security issue. This change aim at mitigating the security issue via allocating sufficent extra memory for each texture allocation for 2D array texture on such devices. Bug: dawn:949 Change-Id: I3629eeb13be872b2107effa55539e5c24522d0fc Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96220 Commit-Queue: Yunchao He <yunchao.he@intel.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
47c22d45ad
commit
122322b532
|
@ -285,6 +285,13 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
|
||||||
"Toggle is enabled by default on the D3D12 platforms where CastingFullyTypedFormatSupported "
|
"Toggle is enabled by default on the D3D12 platforms where CastingFullyTypedFormatSupported "
|
||||||
"is false.",
|
"is false.",
|
||||||
"https://crbug.com/dawn/1276"}},
|
"https://crbug.com/dawn/1276"}},
|
||||||
|
{Toggle::D3D12AllocateExtraMemoryFor2DArrayTexture,
|
||||||
|
{"d3d12_allocate_extra_memory_for_2d_array_texture",
|
||||||
|
"Memory allocation for 2D array texture may be smaller than it should be on D3D12 on some "
|
||||||
|
"Intel devices. So texture access can be out-of-bound, which may cause critical security "
|
||||||
|
"issue. We can workaround this security issue via allocating extra memory and limiting its "
|
||||||
|
"access in itself.",
|
||||||
|
"https://crbug.com/dawn/949"}},
|
||||||
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
|
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
|
||||||
}};
|
}};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -75,6 +75,7 @@ enum class Toggle {
|
||||||
D3D12ForceClearCopyableDepthStencilTextureOnCreation,
|
D3D12ForceClearCopyableDepthStencilTextureOnCreation,
|
||||||
D3D12DontSetClearValueOnDepthTextureCreation,
|
D3D12DontSetClearValueOnDepthTextureCreation,
|
||||||
D3D12AlwaysUseTypelessFormatsForCastableTexture,
|
D3D12AlwaysUseTypelessFormatsForCastableTexture,
|
||||||
|
D3D12AllocateExtraMemoryFor2DArrayTexture,
|
||||||
|
|
||||||
EnumCount,
|
EnumCount,
|
||||||
InvalidEnum = EnumCount,
|
InvalidEnum = EnumCount,
|
||||||
|
|
|
@ -673,6 +673,16 @@ void Device::InitTogglesFromDriver() {
|
||||||
// But we may need to limit it if D3D12 runtime fixes the bug on its new release. See
|
// But we may need to limit it if D3D12 runtime fixes the bug on its new release. See
|
||||||
// https://crbug.com/dawn/1289 for more information.
|
// https://crbug.com/dawn/1289 for more information.
|
||||||
SetToggle(Toggle::D3D12SplitBufferTextureCopyForRowsPerImagePaddings, true);
|
SetToggle(Toggle::D3D12SplitBufferTextureCopyForRowsPerImagePaddings, true);
|
||||||
|
|
||||||
|
// This workaround is only needed on Intel Gen12LP with driver prior to 30.0.101.1960.
|
||||||
|
// See http://crbug.com/dawn/949 for more information.
|
||||||
|
if (gpu_info::IsIntelXe(vendorId, deviceId)) {
|
||||||
|
const gpu_info::D3DDriverVersion version = {30, 0, 101, 1960};
|
||||||
|
if (gpu_info::CompareD3DDriverVersion(vendorId, ToBackend(GetAdapter())->GetDriverVersion(),
|
||||||
|
version) == -1) {
|
||||||
|
SetToggle(Toggle::D3D12AllocateExtraMemoryFor2DArrayTexture, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Device::WaitForIdleForDestruction() {
|
MaybeError Device::WaitForIdleForDestruction() {
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include "dawn/native/d3d12/ResidencyManagerD3D12.h"
|
#include "dawn/native/d3d12/ResidencyManagerD3D12.h"
|
||||||
#include "dawn/native/d3d12/UtilsD3D12.h"
|
#include "dawn/native/d3d12/UtilsD3D12.h"
|
||||||
|
|
||||||
|
static constexpr uint32_t kExtraMemoryToMitigateTextureCorruption = 24576u;
|
||||||
|
|
||||||
namespace dawn::native::d3d12 {
|
namespace dawn::native::d3d12 {
|
||||||
namespace {
|
namespace {
|
||||||
MemorySegment GetMemorySegment(Device* device, D3D12_HEAP_TYPE heapType) {
|
MemorySegment GetMemorySegment(Device* device, D3D12_HEAP_TYPE heapType) {
|
||||||
|
@ -311,6 +313,8 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
|
||||||
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
|
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resourceInfo.SizeInBytes += GetResourcePadding(resourceDescriptor);
|
||||||
|
|
||||||
// If d3d tells us the resource size is invalid, treat the error as OOM.
|
// If d3d tells us the resource size is invalid, treat the error as OOM.
|
||||||
// Otherwise, creating the resource could cause a device loss (too large).
|
// Otherwise, creating the resource could cause a device loss (too large).
|
||||||
// This is because NextPowerOfTwo(UINT64_MAX) overflows and proceeds to
|
// This is because NextPowerOfTwo(UINT64_MAX) overflows and proceeds to
|
||||||
|
@ -333,6 +337,21 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
|
||||||
|
|
||||||
Heap* heap = ToBackend(allocation.GetResourceHeap());
|
Heap* heap = ToBackend(allocation.GetResourceHeap());
|
||||||
|
|
||||||
|
ComPtr<ID3D12Resource> placedResource;
|
||||||
|
DAWN_TRY_ASSIGN(placedResource,
|
||||||
|
CreatePlacedResourceInHeap(heap, allocation.GetOffset(), resourceDescriptor,
|
||||||
|
optimizedClearValue, initialUsage));
|
||||||
|
return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
|
||||||
|
std::move(placedResource), heap};
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultOrError<ComPtr<ID3D12Resource>> ResourceAllocatorManager::CreatePlacedResourceInHeap(
|
||||||
|
Heap* heap,
|
||||||
|
const uint64_t offset,
|
||||||
|
const D3D12_RESOURCE_DESC& resourceDescriptor,
|
||||||
|
const D3D12_CLEAR_VALUE* optimizedClearValue,
|
||||||
|
D3D12_RESOURCE_STATES initialUsage) {
|
||||||
|
ComPtr<ID3D12Resource> placedResource;
|
||||||
// Before calling CreatePlacedResource, we must ensure the target heap is resident.
|
// Before calling CreatePlacedResource, we must ensure the target heap is resident.
|
||||||
// CreatePlacedResource will fail if it is not.
|
// CreatePlacedResource will fail if it is not.
|
||||||
DAWN_TRY(mDevice->GetResidencyManager()->LockAllocation(heap));
|
DAWN_TRY(mDevice->GetResidencyManager()->LockAllocation(heap));
|
||||||
|
@ -344,19 +363,16 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
|
||||||
// within the same command-list and does not require additional synchronization (aliasing
|
// within the same command-list and does not require additional synchronization (aliasing
|
||||||
// barrier).
|
// barrier).
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource
|
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource
|
||||||
ComPtr<ID3D12Resource> placedResource;
|
DAWN_TRY(
|
||||||
DAWN_TRY(CheckOutOfMemoryHRESULT(
|
CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreatePlacedResource(
|
||||||
mDevice->GetD3D12Device()->CreatePlacedResource(
|
heap->GetD3D12Heap(), offset, &resourceDescriptor, initialUsage,
|
||||||
heap->GetD3D12Heap(), allocation.GetOffset(), &resourceDescriptor, initialUsage,
|
optimizedClearValue, IID_PPV_ARGS(&placedResource)),
|
||||||
optimizedClearValue, IID_PPV_ARGS(&placedResource)),
|
"ID3D12Device::CreatePlacedResource"));
|
||||||
"ID3D12Device::CreatePlacedResource"));
|
|
||||||
|
|
||||||
// After CreatePlacedResource has finished, the heap can be unlocked from residency. This
|
// After CreatePlacedResource has finished, the heap can be unlocked from residency. This
|
||||||
// will insert it into the residency LRU.
|
// will insert it into the residency LRU.
|
||||||
mDevice->GetResidencyManager()->UnlockAllocation(heap);
|
mDevice->GetResidencyManager()->UnlockAllocation(heap);
|
||||||
|
return std::move(placedResource);
|
||||||
return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
|
|
||||||
std::move(placedResource), heap};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource(
|
ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource(
|
||||||
|
@ -377,6 +393,10 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
|
||||||
// incorrectly allocate a mismatched size.
|
// incorrectly allocate a mismatched size.
|
||||||
D3D12_RESOURCE_ALLOCATION_INFO resourceInfo =
|
D3D12_RESOURCE_ALLOCATION_INFO resourceInfo =
|
||||||
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
|
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
|
||||||
|
|
||||||
|
uint64_t extraMemory = GetResourcePadding(resourceDescriptor);
|
||||||
|
resourceInfo.SizeInBytes += extraMemory;
|
||||||
|
|
||||||
if (resourceInfo.SizeInBytes == 0 ||
|
if (resourceInfo.SizeInBytes == 0 ||
|
||||||
resourceInfo.SizeInBytes == std::numeric_limits<uint64_t>::max()) {
|
resourceInfo.SizeInBytes == std::numeric_limits<uint64_t>::max()) {
|
||||||
return DAWN_OUT_OF_MEMORY_ERROR("Resource allocation size was invalid.");
|
return DAWN_OUT_OF_MEMORY_ERROR("Resource allocation size was invalid.");
|
||||||
|
@ -395,11 +415,23 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
|
||||||
// Note: Heap flags are inferred by the resource descriptor and do not need to be explicitly
|
// Note: Heap flags are inferred by the resource descriptor and do not need to be explicitly
|
||||||
// provided to CreateCommittedResource.
|
// provided to CreateCommittedResource.
|
||||||
ComPtr<ID3D12Resource> committedResource;
|
ComPtr<ID3D12Resource> committedResource;
|
||||||
DAWN_TRY(CheckOutOfMemoryHRESULT(
|
if (extraMemory > 0) {
|
||||||
mDevice->GetD3D12Device()->CreateCommittedResource(
|
const ResourceHeapKind resourceHeapKind = GetResourceHeapKind(
|
||||||
&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDescriptor, initialUsage,
|
resourceDescriptor.Dimension, heapType, resourceDescriptor.Flags, mResourceHeapTier);
|
||||||
optimizedClearValue, IID_PPV_ARGS(&committedResource)),
|
std::unique_ptr<ResourceHeapBase> heapBase;
|
||||||
"ID3D12Device::CreateCommittedResource"));
|
DAWN_TRY_ASSIGN(heapBase, mPooledHeapAllocators[resourceHeapKind]->AllocateResourceHeap(
|
||||||
|
resourceInfo.SizeInBytes));
|
||||||
|
Heap* heap = ToBackend(heapBase.get());
|
||||||
|
DAWN_TRY_ASSIGN(committedResource,
|
||||||
|
CreatePlacedResourceInHeap(heap, 0, resourceDescriptor, optimizedClearValue,
|
||||||
|
initialUsage));
|
||||||
|
} else {
|
||||||
|
DAWN_TRY(CheckOutOfMemoryHRESULT(
|
||||||
|
mDevice->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDescriptor, initialUsage,
|
||||||
|
optimizedClearValue, IID_PPV_ARGS(&committedResource)),
|
||||||
|
"ID3D12Device::CreateCommittedResource"));
|
||||||
|
}
|
||||||
|
|
||||||
// When using CreateCommittedResource, D3D12 creates an implicit heap that contains the
|
// When using CreateCommittedResource, D3D12 creates an implicit heap that contains the
|
||||||
// resource allocation. Because Dawn's memory residency management occurs at the resource
|
// resource allocation. Because Dawn's memory residency management occurs at the resource
|
||||||
|
@ -420,6 +452,17 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
|
||||||
/*offset*/ 0, std::move(committedResource), heap};
|
/*offset*/ 0, std::move(committedResource), heap};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t ResourceAllocatorManager::GetResourcePadding(
|
||||||
|
const D3D12_RESOURCE_DESC& resourceDescriptor) const {
|
||||||
|
// If we are allocating memory for a 2D array texture on D3D12 backend, we need to allocate
|
||||||
|
// extra memory on some devices, see crbug.com/dawn/949 for details.
|
||||||
|
if (mDevice->IsToggleEnabled(Toggle::D3D12AllocateExtraMemoryFor2DArrayTexture) &&
|
||||||
|
resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
|
||||||
|
resourceDescriptor.DepthOrArraySize > 1) {
|
||||||
|
return kExtraMemoryToMitigateTextureCorruption;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
void ResourceAllocatorManager::DestroyPool() {
|
void ResourceAllocatorManager::DestroyPool() {
|
||||||
for (auto& alloc : mPooledHeapAllocators) {
|
for (auto& alloc : mPooledHeapAllocators) {
|
||||||
alloc->DestroyPool();
|
alloc->DestroyPool();
|
||||||
|
|
|
@ -86,6 +86,15 @@ class ResourceAllocatorManager {
|
||||||
const D3D12_CLEAR_VALUE* optimizedClearValue,
|
const D3D12_CLEAR_VALUE* optimizedClearValue,
|
||||||
D3D12_RESOURCE_STATES initialUsage);
|
D3D12_RESOURCE_STATES initialUsage);
|
||||||
|
|
||||||
|
ResultOrError<ComPtr<ID3D12Resource>> CreatePlacedResourceInHeap(
|
||||||
|
Heap* heap,
|
||||||
|
const uint64_t offset,
|
||||||
|
const D3D12_RESOURCE_DESC& resourceDescriptor,
|
||||||
|
const D3D12_CLEAR_VALUE* optimizedClearValue,
|
||||||
|
D3D12_RESOURCE_STATES initialUsage);
|
||||||
|
|
||||||
|
uint64_t GetResourcePadding(const D3D12_RESOURCE_DESC& resourceDescriptor) const;
|
||||||
|
|
||||||
Device* mDevice;
|
Device* mDevice;
|
||||||
uint32_t mResourceHeapTier;
|
uint32_t mResourceHeapTier;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue