Skip to content

Commit

Permalink
Validate execute data
Browse files Browse the repository at this point in the history
  • Loading branch information
elishacloud committed Jan 14, 2025
1 parent 478b334 commit 2a169c6
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 7421
#define BUILD_NUMBER 7422
101 changes: 97 additions & 4 deletions ddraw/IDirect3DExecuteBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ HRESULT m_IDirect3DExecuteBuffer::Lock(LPD3DEXECUTEBUFFERDESC lpDesc)
// Mark the buffer as locked
IsLocked = true;

return DD_OK;
// Mark data as unvalidated
IsDataValidated = false;

return D3D_OK;
}

return ProxyInterface->Lock(lpDesc);
Expand Down Expand Up @@ -237,12 +240,55 @@ HRESULT m_IDirect3DExecuteBuffer::Unlock()
IsLocked = false;

// No specific action required, just return success
return DD_OK;
return D3D_OK;
}

return ProxyInterface->Unlock();
}

HRESULT m_IDirect3DExecuteBuffer::ValidateInstructionData(const void* lpData, DWORD dwInstructionOffset, DWORD dwInstructionLength)
{
const BYTE* data = (const BYTE*)lpData + dwInstructionOffset;
DWORD offset = 0;

while (offset < dwInstructionLength)
{
if (offset + sizeof(D3DINSTRUCTION) > dwInstructionLength)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Instruction header exceeds bounds!");
return DDERR_INVALIDPARAMS;
}

const D3DINSTRUCTION* instruction = (const D3DINSTRUCTION*)(data + offset);

if (instruction->bOpcode == 0 || instruction->bOpcode > 14)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Invalid opcode: " << instruction->bOpcode);
return DDERR_INVALIDPARAMS;
}

DWORD instructionSize = sizeof(D3DINSTRUCTION) + (instruction->wCount * instruction->bSize);
if (offset + instructionSize > dwInstructionLength)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Instruction data exceeds bounds!");
return DDERR_INVALIDPARAMS;
}

if (instruction->bOpcode == D3DOP_EXIT)
{
// Valid and terminated properly
IsDataValidated = true;
return D3D_OK;
}

// Move to the next instruction
offset += instructionSize;
}

LOG_LIMIT(100, __FUNCTION__ << " Error: Missing D3DOP_EXIT!");
return DDERR_INVALIDPARAMS;
}

HRESULT m_IDirect3DExecuteBuffer::SetExecuteData(LPD3DEXECUTEDATA lpData)
{
Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
Expand Down Expand Up @@ -272,10 +318,39 @@ HRESULT m_IDirect3DExecuteBuffer::SetExecuteData(LPD3DEXECUTEDATA lpData)
return D3DERR_EXECUTE_LOCKED;
}

// Ensure that the instruction range is within the bounds of the execute buffer
if (lpData->dwInstructionOffset + lpData->dwInstructionLength > Desc.dwBufferSize)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Invalid instruction range!");
return DDERR_INVALIDPARAMS;
}

// Ensure the vertex data lies within the buffer and does not overlap with instructions
if (lpData->dwVertexOffset + lpData->dwVertexCount * sizeof(D3DVERTEX) > Desc.dwBufferSize)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Invalid vertex range!");
return DDERR_INVALIDPARAMS;
}

// Ensure the data segments (vertices and instructions) do not overlap unintentionally
if (lpData->dwVertexOffset < lpData->dwInstructionOffset + lpData->dwInstructionLength &&
lpData->dwVertexOffset + lpData->dwVertexCount * sizeof(D3DVERTEX) > lpData->dwInstructionOffset)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Overlapping data regions!");
return DDERR_INVALIDPARAMS;
}

// Validate instruction data
HRESULT hr = ValidateInstructionData(Desc.lpData, lpData->dwInstructionOffset, lpData->dwInstructionLength);
if (FAILED(hr))
{
return hr;
}

// Store execute data
ExecuteData = *lpData;

return DD_OK;
return D3D_OK;
}

return ProxyInterface->SetExecuteData(lpData);
Expand Down Expand Up @@ -313,12 +388,29 @@ HRESULT m_IDirect3DExecuteBuffer::GetExecuteData(LPD3DEXECUTEDATA lpData)
// Return stored execute data
*lpData = ExecuteData;

return DD_OK;
return D3D_OK;
}

return ProxyInterface->GetExecuteData(lpData);
}

HRESULT m_IDirect3DExecuteBuffer::GetExecuteData(D3DEXECUTEBUFFERDESC& CurrentDesc, D3DEXECUTEDATA& CurrentExecuteData)
{
if (!IsDataValidated)
{
HRESULT hr = ValidateInstructionData(&Desc, ExecuteData.dwInstructionOffset, ExecuteData.dwInstructionLength);
if (FAILED(hr))
{
return hr;
}
}

CurrentDesc = Desc;
CurrentExecuteData = ExecuteData;

return D3D_OK;
}

HRESULT m_IDirect3DExecuteBuffer::Validate(LPDWORD lpdwOffset, LPD3DVALIDATECALLBACK lpFunc, LPVOID lpUserArg, DWORD dwReserved)
{
Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
Expand Down Expand Up @@ -362,6 +454,7 @@ HRESULT m_IDirect3DExecuteBuffer::Optimize(DWORD dwDummy)
void m_IDirect3DExecuteBuffer::InitInterface(LPD3DEXECUTEBUFFERDESC lpDesc)
{
IsLocked = false;
IsDataValidated = false;
ExecuteData = {};
ExecuteData.dwSize = sizeof(D3DEXECUTEDATA);
Desc = {};
Expand Down
9 changes: 8 additions & 1 deletion ddraw/IDirect3DExecuteBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ class m_IDirect3DExecuteBuffer : public IDirect3DExecuteBuffer, public AddressLo
m_IDirect3DDeviceX *D3DDeviceInterface = nullptr;
D3DEXECUTEBUFFERDESC Desc = {};
std::vector<BYTE> MemoryData;
bool IsLocked = false;
D3DEXECUTEDATA ExecuteData = {};
bool IsLocked = false;
bool IsDataValidated = false;

// Instruction data
HRESULT ValidateInstructionData(const void* lpData, DWORD dwInstructionOffset, DWORD dwInstructionLength);

// Interface initialization functions
void InitInterface(LPD3DEXECUTEBUFFERDESC lpDesc);
Expand Down Expand Up @@ -76,4 +80,7 @@ class m_IDirect3DExecuteBuffer : public IDirect3DExecuteBuffer, public AddressLo
STDMETHOD(GetExecuteData)(THIS_ LPD3DEXECUTEDATA);
STDMETHOD(Validate)(THIS_ LPDWORD, LPD3DVALIDATECALLBACK, LPVOID, DWORD);
STDMETHOD(Optimize)(THIS_ DWORD);

// Helper functions
HRESULT GetExecuteData(D3DEXECUTEBUFFERDESC& CurrentDesc, D3DEXECUTEDATA& CurrentExecuteData);
};

0 comments on commit 2a169c6

Please sign in to comment.