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 "
|
||||
"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
|
||||
|
|
|
@ -75,6 +75,7 @@ enum class Toggle {
|
|||
D3D12ForceClearCopyableDepthStencilTextureOnCreation,
|
||||
D3D12DontSetClearValueOnDepthTextureCreation,
|
||||
D3D12AlwaysUseTypelessFormatsForCastableTexture,
|
||||
D3D12AllocateExtraMemoryFor2DArrayTexture,
|
||||
|
||||
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
|
||||
// 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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue