Skip to content

Commit 6e4ace3

Browse files
lmurrayslouken
authored andcommitted
GPU: Validate shader bytecode
1 parent 89d7d40 commit 6e4ace3

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

src/gpu/d3d12/SDL_gpu_d3d12.c

+25
Original file line numberDiff line numberDiff line change
@@ -2482,12 +2482,32 @@ static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature(
24822482
return d3d12GraphicsRootSignature;
24832483
}
24842484

2485+
static bool D3D12_INTERNAL_IsValidShaderBytecode(
2486+
const Uint8 *code,
2487+
size_t codeSize)
2488+
{
2489+
// Both DXIL and DXBC bytecode have a 4 byte header containing `DXBC`.
2490+
if (codeSize < 4 || code == NULL) {
2491+
return false;
2492+
}
2493+
return SDL_memcmp(code, "DXBC", 4) == 0;
2494+
}
2495+
24852496
static bool D3D12_INTERNAL_CreateShaderBytecode(
2497+
D3D12Renderer *renderer,
24862498
const Uint8 *code,
24872499
size_t codeSize,
2500+
SDL_GPUShaderFormat format,
24882501
void **pBytecode,
24892502
size_t *pBytecodeSize)
24902503
{
2504+
if (!D3D12_INTERNAL_IsValidShaderBytecode(code, codeSize)) {
2505+
if (format == SDL_GPU_SHADERFORMAT_DXBC) {
2506+
SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid DXBC!", false);
2507+
}
2508+
SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid DXIL!", false);
2509+
}
2510+
24912511
if (pBytecode != NULL) {
24922512
*pBytecode = SDL_malloc(codeSize);
24932513
if (!*pBytecode) {
@@ -2705,8 +2725,10 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline(
27052725
ID3D12PipelineState *pipelineState;
27062726

27072727
if (!D3D12_INTERNAL_CreateShaderBytecode(
2728+
renderer,
27082729
createinfo->code,
27092730
createinfo->code_size,
2731+
createinfo->format,
27102732
&bytecode,
27112733
&bytecodeSize)) {
27122734
return NULL;
@@ -3113,13 +3135,16 @@ static SDL_GPUShader *D3D12_CreateShader(
31133135
SDL_GPURenderer *driverData,
31143136
const SDL_GPUShaderCreateInfo *createinfo)
31153137
{
3138+
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
31163139
void *bytecode;
31173140
size_t bytecodeSize;
31183141
D3D12Shader *shader;
31193142

31203143
if (!D3D12_INTERNAL_CreateShaderBytecode(
3144+
renderer,
31213145
createinfo->code,
31223146
createinfo->code_size,
3147+
createinfo->format,
31233148
&bytecode,
31243149
&bytecodeSize)) {
31253150
return NULL;

src/gpu/metal/SDL_gpu_metal.m

+16
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,17 @@ static void METAL_INTERNAL_TrackUniformBuffer(
836836
id<MTLFunction> function;
837837
} MetalLibraryFunction;
838838

839+
static bool METAL_INTERNAL_IsValidMetalLibrary(
840+
const Uint8 *code,
841+
size_t codeSize)
842+
{
843+
// Metal libraries have a 4 byte header containing `MTLB`.
844+
if (codeSize < 4 || code == NULL) {
845+
return false;
846+
}
847+
return SDL_memcmp(code, "MTLB", 4) == 0;
848+
}
849+
839850
// This function assumes that it's called from within an autorelease pool
840851
static MetalLibraryFunction METAL_INTERNAL_CompileShader(
841852
MetalRenderer *renderer,
@@ -864,6 +875,11 @@ static MetalLibraryFunction METAL_INTERNAL_CompileShader(
864875
options:nil
865876
error:&error];
866877
} else if (format == SDL_GPU_SHADERFORMAT_METALLIB) {
878+
if (!METAL_INTERNAL_IsValidMetalLibrary(code, codeSize)) {
879+
SET_STRING_ERROR_AND_RETURN(
880+
"The provided shader code is not a valid Metal library!",
881+
libraryFunction);
882+
}
867883
data = dispatch_data_create(
868884
code,
869885
codeSize,

src/gpu/vulkan/SDL_gpu_vulkan.c

+27
Original file line numberDiff line numberDiff line change
@@ -6511,6 +6511,25 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
65116511
return (SDL_GPUGraphicsPipeline *)graphicsPipeline;
65126512
}
65136513

6514+
static bool VULKAN_INTERNAL_IsValidShaderBytecode(
6515+
const Uint8 *code,
6516+
size_t codeSize)
6517+
{
6518+
// SPIR-V bytecode has a 4 byte header containing 0x07230203. SPIR-V is
6519+
// defined as a stream of words and not a stream of bytes so both byte
6520+
// orders need to be considered.
6521+
//
6522+
// FIXME: It is uncertain if drivers are able to load both byte orders. If
6523+
// needed we may need to do an optional swizzle internally so apps can
6524+
// continue to treat shader code as an opaque blob.
6525+
if (codeSize < 4 || code == NULL) {
6526+
return false;
6527+
}
6528+
const Uint32 magic = 0x07230203;
6529+
const Uint32 magicInv = 0x03022307;
6530+
return SDL_memcmp(code, &magic, 4) == 0 || SDL_memcmp(code, &magicInv, 4) == 0;
6531+
}
6532+
65146533
static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
65156534
SDL_GPURenderer *driverData,
65166535
const SDL_GPUComputePipelineCreateInfo *createinfo)
@@ -6526,6 +6545,10 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
65266545
SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL);
65276546
}
65286547

6548+
if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) {
6549+
SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL);
6550+
}
6551+
65296552
vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline));
65306553
shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
65316554
shaderModuleCreateInfo.pNext = NULL;
@@ -6671,6 +6694,10 @@ static SDL_GPUShader *VULKAN_CreateShader(
66716694
VkShaderModuleCreateInfo vkShaderModuleCreateInfo;
66726695
VulkanRenderer *renderer = (VulkanRenderer *)driverData;
66736696

6697+
if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) {
6698+
SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL);
6699+
}
6700+
66746701
vulkanShader = SDL_malloc(sizeof(VulkanShader));
66756702
vkShaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
66766703
vkShaderModuleCreateInfo.pNext = NULL;

0 commit comments

Comments
 (0)