Add safety checks to material constants binding code to prevent invalid memory access

This commit is contained in:
Wojtek Figat
2021-07-06 15:41:16 +02:00
parent 9f9d946d69
commit a165b4aa79
14 changed files with 85 additions and 55 deletions

View File

@@ -36,9 +36,10 @@ void DecalMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<DecalMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(DecalMaterialShaderData));
cb += sizeof(DecalMaterialShaderData); auto materialData = reinterpret_cast<DecalMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(DecalMaterialShaderData), cb.Length() - sizeof(DecalMaterialShaderData));
int32 srv = 0; int32 srv = 0;
const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains; const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains;

View File

@@ -60,9 +60,10 @@ void DeferredMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(DeferredMaterialShaderData));
cb += sizeof(DeferredMaterialShaderData); auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(DeferredMaterialShaderData), cb.Length() - sizeof(DeferredMaterialShaderData));
int32 srv = 2; int32 srv = 2;
// Setup features // Setup features

View File

@@ -47,9 +47,10 @@ void DeformableMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<DeformableMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(DeformableMaterialShaderData));
cb += sizeof(DeformableMaterialShaderData); auto materialData = reinterpret_cast<DeformableMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(DeformableMaterialShaderData), cb.Length() - sizeof(DeformableMaterialShaderData));
int32 srv = 1; int32 srv = 1;
// Setup features // Setup features

View File

@@ -57,9 +57,10 @@ void ForwardMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(ForwardMaterialShaderData));
cb += sizeof(ForwardMaterialShaderData); auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(ForwardMaterialShaderData), cb.Length() - sizeof(ForwardMaterialShaderData));
int32 srv = 2; int32 srv = 2;
// Setup features // Setup features

View File

@@ -26,9 +26,10 @@ void GUIMaterialShader::Bind(BindParameters& params)
{ {
// Prepare // Prepare
auto context = params.GPUContext; auto context = params.GPUContext;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<GUIMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(GUIMaterialShaderData));
cb += sizeof(GUIMaterialShaderData); auto materialData = reinterpret_cast<GUIMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(GUIMaterialShaderData), cb.Length() - sizeof(GUIMaterialShaderData));
int32 srv = 0; int32 srv = 0;
const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth; const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth;

View File

@@ -317,28 +317,36 @@ void MaterialParameter::Bind(BindMeta& meta) const
switch (_type) switch (_type)
{ {
case MaterialParameterType::Bool: case MaterialParameterType::Bool:
*((int32*)(meta.Constants + _offset)) = _asBool; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(bool));
*((int32*)(meta.Constants.Get() + _offset)) = _asBool;
break; break;
case MaterialParameterType::Integer: case MaterialParameterType::Integer:
*((int32*)(meta.Constants + _offset)) = _asInteger; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
*((int32*)(meta.Constants.Get() + _offset)) = _asInteger;
break; break;
case MaterialParameterType::Float: case MaterialParameterType::Float:
*((float*)(meta.Constants + _offset)) = _asFloat; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(float));
*((float*)(meta.Constants.Get() + _offset)) = _asFloat;
break; break;
case MaterialParameterType::Vector2: case MaterialParameterType::Vector2:
*((Vector2*)(meta.Constants + _offset)) = _asVector2; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector2));
*((Vector2*)(meta.Constants.Get() + _offset)) = _asVector2;
break; break;
case MaterialParameterType::Vector3: case MaterialParameterType::Vector3:
*((Vector3*)(meta.Constants + _offset)) = _asVector3; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector3));
*((Vector3*)(meta.Constants.Get() + _offset)) = _asVector3;
break; break;
case MaterialParameterType::Vector4: case MaterialParameterType::Vector4:
*((Vector4*)(meta.Constants + _offset)) = *(Vector4*)&AsData; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector4));
*((Vector4*)(meta.Constants.Get() + _offset)) = *(Vector4*)&AsData;
break; break;
case MaterialParameterType::Color: case MaterialParameterType::Color:
*((Color*)(meta.Constants + _offset)) = _asColor; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector4));
*((Color*)(meta.Constants.Get() + _offset)) = _asColor;
break; break;
case MaterialParameterType::Matrix: case MaterialParameterType::Matrix:
Matrix::Transpose(*(Matrix*)&AsData, *(Matrix*)(meta.Constants + _offset)); ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Matrix));
Matrix::Transpose(*(Matrix*)&AsData, *(Matrix*)(meta.Constants.Get() + _offset));
break; break;
case MaterialParameterType::NormalMap: case MaterialParameterType::NormalMap:
{ {
@@ -415,7 +423,8 @@ void MaterialParameter::Bind(BindMeta& meta) const
break; break;
} }
case MaterialParameterType::ChannelMask: case MaterialParameterType::ChannelMask:
*((Vector4*)(meta.Constants + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3); ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
*((Vector4*)(meta.Constants.Get() + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3);
break; break;
case MaterialParameterType::GameplayGlobal: case MaterialParameterType::GameplayGlobal:
if (_asAsset) if (_asAsset)
@@ -426,26 +435,33 @@ void MaterialParameter::Bind(BindMeta& meta) const
switch (e->Value.Type.Type) switch (e->Value.Type.Type)
{ {
case VariantType::Bool: case VariantType::Bool:
*((bool*)(meta.Constants + _offset)) = e->Value.AsBool; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(bool));
*((bool*)(meta.Constants.Get() + _offset)) = e->Value.AsBool;
break; break;
case VariantType::Int: case VariantType::Int:
*((int32*)(meta.Constants + _offset)) = e->Value.AsInt; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
*((int32*)(meta.Constants.Get() + _offset)) = e->Value.AsInt;
break; break;
case VariantType::Uint: case VariantType::Uint:
*((uint32*)(meta.Constants + _offset)) = e->Value.AsUint; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(uint32));
*((uint32*)(meta.Constants.Get() + _offset)) = e->Value.AsUint;
break; break;
case VariantType::Float: case VariantType::Float:
*((float*)(meta.Constants + _offset)) = e->Value.AsFloat; ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(float));
*((float*)(meta.Constants.Get() + _offset)) = e->Value.AsFloat;
break; break;
case VariantType::Vector2: case VariantType::Vector2:
*((Vector2*)(meta.Constants + _offset)) = e->Value.AsVector2(); ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector2));
*((Vector2*)(meta.Constants.Get() + _offset)) = e->Value.AsVector2();
break; break;
case VariantType::Vector3: case VariantType::Vector3:
*((Vector3*)(meta.Constants + _offset)) = e->Value.AsVector3(); ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector3));
*((Vector3*)(meta.Constants.Get() + _offset)) = e->Value.AsVector3();
break; break;
case VariantType::Vector4: case VariantType::Vector4:
case VariantType::Color: case VariantType::Color:
*((Vector4*)(meta.Constants + _offset)) = e->Value.AsVector4(); ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector4));
*((Vector4*)(meta.Constants.Get() + _offset)) = e->Value.AsVector4();
break; break;
default: ; default: ;
} }

View File

@@ -309,7 +309,7 @@ public:
/// <summary> /// <summary>
/// The pointer to the constants buffer in the memory. /// The pointer to the constants buffer in the memory.
/// </summary> /// </summary>
byte* Constants; Span<byte> Constants;
/// <summary> /// <summary>
/// The input scene color. It's optional and used in forward/postFx rendering. /// The input scene color. It's optional and used in forward/postFx rendering.

View File

@@ -11,13 +11,14 @@
#include "Engine/Level/Scene/Lightmap.h" #include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Level/Actors/EnvironmentProbe.h" #include "Engine/Level/Actors/EnvironmentProbe.h"
void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv) void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv)
{ {
auto context = params.GPUContext; auto context = params.GPUContext;
auto cache = params.RenderContext.List; auto cache = params.RenderContext.List;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
auto& data = *(Data*)cb; auto& data = *(Data*)cb.Get();
ASSERT_LOW_LAYER(cb.Length() >= sizeof(Data));
const int32 envProbeShaderRegisterIndex = srv + 0; const int32 envProbeShaderRegisterIndex = srv + 0;
const int32 skyLightShaderRegisterIndex = srv + 1; const int32 skyLightShaderRegisterIndex = srv + 1;
const int32 dirLightShaderRegisterIndex = srv + 2; const int32 dirLightShaderRegisterIndex = srv + 2;
@@ -116,16 +117,17 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, byte*&
} }
} }
cb += sizeof(Data); cb = Span<byte>(cb.Get() + sizeof(Data), cb.Length() - sizeof(Data));
srv += SRVs; srv += SRVs;
} }
bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv) bool LightmapFeature::Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv)
{ {
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
auto& data = *(Data*)cb; auto& data = *(Data*)cb.Get();
ASSERT_LOW_LAYER(cb.Length() >= sizeof(Data));
const bool useLightmap = view.Flags & ViewFlags::GI const bool useLightmap = view.Flags & ViewFlags::GI
#if USE_EDITOR #if USE_EDITOR
@@ -145,8 +147,8 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, in
data.LightmapArea = drawCall.Features.LightmapUVsArea; data.LightmapArea = drawCall.Features.LightmapUVsArea;
} }
cb = Span<byte>(cb.Get() + sizeof(Data), cb.Length() - sizeof(Data));
srv += SRVs; srv += SRVs;
cb += sizeof(Data);
return useLightmap; return useLightmap;
} }

View File

@@ -4,6 +4,7 @@
#include "MaterialShader.h" #include "MaterialShader.h"
#include "Engine/Core/Math/Rectangle.h" #include "Engine/Core/Math/Rectangle.h"
#include "Engine/Core/Types/Span.h"
// Material shader features are plugin-based functionalities that are reusable between different material domains. // Material shader features are plugin-based functionalities that are reusable between different material domains.
struct MaterialShaderFeature struct MaterialShaderFeature
@@ -35,7 +36,7 @@ struct ForwardShadingFeature : MaterialShaderFeature
LightData LocalLights[MaxLocalLights]; LightData LocalLights[MaxLocalLights];
}); });
static void Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv); static void Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv);
#if USE_EDITOR #if USE_EDITOR
static void Generate(GeneratorData& data); static void Generate(GeneratorData& data);
#endif #endif
@@ -67,7 +68,7 @@ struct LightmapFeature : MaterialShaderFeature
Rectangle LightmapArea; Rectangle LightmapArea;
}); });
static bool Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv); static bool Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv);
#if USE_EDITOR #if USE_EDITOR
static void Generate(GeneratorData& data); static void Generate(GeneratorData& data);
#endif #endif

View File

@@ -57,9 +57,10 @@ void ParticleMaterialShader::Bind(BindParameters& params)
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset; const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(ParticleMaterialShaderData));
cb += sizeof(ParticleMaterialShaderData); auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(ParticleMaterialShaderData), cb.Length() - sizeof(ParticleMaterialShaderData));
int32 srv = 2; int32 srv = 2;
// Setup features // Setup features
@@ -89,7 +90,8 @@ void ParticleMaterialShader::Bind(BindParameters& params)
{ {
const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9); const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9);
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name); const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset; ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)param.GetBindOffset() + sizeof(int32));
*((int32*)(bindMeta.Constants.Get() + param.GetBindOffset())) = offset;
} }
} }
} }

View File

@@ -25,9 +25,10 @@ void PostFxMaterialShader::Bind(BindParameters& params)
// Prepare // Prepare
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(PostFxMaterialShaderData));
cb += sizeof(PostFxMaterialShaderData); auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(PostFxMaterialShaderData), cb.Length() - sizeof(PostFxMaterialShaderData));
int32 srv = 0; int32 srv = 0;
// Setup parameters // Setup parameters

View File

@@ -53,9 +53,10 @@ void TerrainMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<TerrainMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(TerrainMaterialShaderData));
cb += sizeof(TerrainMaterialShaderData); auto materialData = reinterpret_cast<TerrainMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(TerrainMaterialShaderData), cb.Length() - sizeof(TerrainMaterialShaderData));
int32 srv = 3; int32 srv = 3;
// Setup features // Setup features

View File

@@ -45,9 +45,10 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get(); Span<byte> cb(_cbData.Get(), _cbData.Count());
auto materialData = reinterpret_cast<VolumeParticleMaterialShaderData*>(cb); ASSERT_LOW_LAYER(cb.Length() >= sizeof(VolumeParticleMaterialShaderData));
cb += sizeof(VolumeParticleMaterialShaderData); auto materialData = reinterpret_cast<VolumeParticleMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(VolumeParticleMaterialShaderData), cb.Length() - sizeof(VolumeParticleMaterialShaderData));
int32 srv = 1; int32 srv = 1;
auto customData = (VolumetricFogPass::CustomData*)params.CustomData; auto customData = (VolumetricFogPass::CustomData*)params.CustomData;
@@ -74,7 +75,8 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params)
{ {
const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9); const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9);
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name); const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset; ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)param.GetBindOffset() + sizeof(int32));
*((int32*)(bindMeta.Constants.Get() + param.GetBindOffset())) = offset;
} }
} }
} }

View File

@@ -162,7 +162,7 @@ void GPUParticles::Execute(GPUContext* context, ParticleEmitter* emitter, Partic
// Setup parameters // Setup parameters
MaterialParameter::BindMeta bindMeta; MaterialParameter::BindMeta bindMeta;
bindMeta.Context = context; bindMeta.Context = context;
bindMeta.Constants = hasCB ? _cbData.Get() + sizeof(GPUParticlesData) : nullptr; bindMeta.Constants = hasCB ? Span<byte>(_cbData.Get() + sizeof(GPUParticlesData), _cbData.Count() - sizeof(GPUParticlesData)) : Span<byte>(nullptr, 0);
bindMeta.Input = nullptr; bindMeta.Input = nullptr;
if (viewTask) if (viewTask)
{ {