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:
Yunchao He 2022-07-30 07:00:33 +00:00 committed by Dawn LUCI CQ
parent 47c22d45ad
commit 122322b532
5 changed files with 84 additions and 14 deletions

View File

@ -285,6 +285,13 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
"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

View File

@ -75,6 +75,7 @@ enum class Toggle {
D3D12ForceClearCopyableDepthStencilTextureOnCreation,
D3D12DontSetClearValueOnDepthTextureCreation,
D3D12AlwaysUseTypelessFormatsForCastableTexture,
D3D12AllocateExtraMemoryFor2DArrayTexture,
EnumCount,
InvalidEnum = EnumCount,

View File

@ -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
// 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() {

View File

@ -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 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
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 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
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 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
// 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 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
// 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 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
// 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 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
/*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();

View File

@ -86,6 +86,15 @@ class ResourceAllocatorManager {
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;