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>
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp
index a04bfce..55ac82f 100644
--- a/src/dawn/native/Toggles.cpp
+++ b/src/dawn/native/Toggles.cpp
@@ -285,6 +285,13 @@
"Toggle is enabled by default on the D3D12 platforms where CastingFullyTypedFormatSupported "
"is false.",
"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.
}};
} // anonymous namespace
diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h
index 77f7d07..32aa009 100644
--- a/src/dawn/native/Toggles.h
+++ b/src/dawn/native/Toggles.h
@@ -75,6 +75,7 @@
D3D12ForceClearCopyableDepthStencilTextureOnCreation,
D3D12DontSetClearValueOnDepthTextureCreation,
D3D12AlwaysUseTypelessFormatsForCastableTexture,
+ D3D12AllocateExtraMemoryFor2DArrayTexture,
EnumCount,
InvalidEnum = EnumCount,
diff --git a/src/dawn/native/d3d12/DeviceD3D12.cpp b/src/dawn/native/d3d12/DeviceD3D12.cpp
index ef6baec..10846ba 100644
--- a/src/dawn/native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/DeviceD3D12.cpp
@@ -673,6 +673,16 @@
// 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.
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() {
diff --git a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
index 454b924..d1f8b26 100644
--- a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
+++ b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
@@ -24,6 +24,8 @@
#include "dawn/native/d3d12/ResidencyManagerD3D12.h"
#include "dawn/native/d3d12/UtilsD3D12.h"
+static constexpr uint32_t kExtraMemoryToMitigateTextureCorruption = 24576u;
+
namespace dawn::native::d3d12 {
namespace {
MemorySegment GetMemorySegment(Device* device, D3D12_HEAP_TYPE heapType) {
@@ -311,6 +313,8 @@
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
}
+ resourceInfo.SizeInBytes += GetResourcePadding(resourceDescriptor);
+
// 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).
// This is because NextPowerOfTwo(UINT64_MAX) overflows and proceeds to
@@ -333,6 +337,21 @@
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.
// CreatePlacedResource will fail if it is not.
DAWN_TRY(mDevice->GetResidencyManager()->LockAllocation(heap));
@@ -344,19 +363,16 @@
// within the same command-list and does not require additional synchronization (aliasing
// barrier).
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource
- ComPtr<ID3D12Resource> placedResource;
- DAWN_TRY(CheckOutOfMemoryHRESULT(
- mDevice->GetD3D12Device()->CreatePlacedResource(
- heap->GetD3D12Heap(), allocation.GetOffset(), &resourceDescriptor, initialUsage,
- optimizedClearValue, IID_PPV_ARGS(&placedResource)),
- "ID3D12Device::CreatePlacedResource"));
+ DAWN_TRY(
+ CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreatePlacedResource(
+ heap->GetD3D12Heap(), offset, &resourceDescriptor, initialUsage,
+ optimizedClearValue, IID_PPV_ARGS(&placedResource)),
+ "ID3D12Device::CreatePlacedResource"));
// After CreatePlacedResource has finished, the heap can be unlocked from residency. This
// will insert it into the residency LRU.
mDevice->GetResidencyManager()->UnlockAllocation(heap);
-
- return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
- std::move(placedResource), heap};
+ return std::move(placedResource);
}
ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource(
@@ -377,6 +393,10 @@
// incorrectly allocate a mismatched size.
D3D12_RESOURCE_ALLOCATION_INFO resourceInfo =
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
+
+ uint64_t extraMemory = GetResourcePadding(resourceDescriptor);
+ resourceInfo.SizeInBytes += extraMemory;
+
if (resourceInfo.SizeInBytes == 0 ||
resourceInfo.SizeInBytes == std::numeric_limits<uint64_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Resource allocation size was invalid.");
@@ -395,11 +415,23 @@
// Note: Heap flags are inferred by the resource descriptor and do not need to be explicitly
// provided to CreateCommittedResource.
ComPtr<ID3D12Resource> committedResource;
- DAWN_TRY(CheckOutOfMemoryHRESULT(
- mDevice->GetD3D12Device()->CreateCommittedResource(
- &heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDescriptor, initialUsage,
- optimizedClearValue, IID_PPV_ARGS(&committedResource)),
- "ID3D12Device::CreateCommittedResource"));
+ if (extraMemory > 0) {
+ const ResourceHeapKind resourceHeapKind = GetResourceHeapKind(
+ resourceDescriptor.Dimension, heapType, resourceDescriptor.Flags, mResourceHeapTier);
+ std::unique_ptr<ResourceHeapBase> heapBase;
+ 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
// resource allocation. Because Dawn's memory residency management occurs at the resource
@@ -420,6 +452,17 @@
/*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() {
for (auto& alloc : mPooledHeapAllocators) {
alloc->DestroyPool();
diff --git a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h
index 5b6dfd8..7bb454d 100644
--- a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h
+++ b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h
@@ -86,6 +86,15 @@
const D3D12_CLEAR_VALUE* optimizedClearValue,
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;
uint32_t mResourceHeapTier;