Skip to content

Commit df92b1d

Browse files
acts-1631elad335
authored andcommitted
Bounds-check Cg binary byte swapping
1 parent 0514f52 commit df92b1d

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

rpcs3/Emu/RSX/Program/CgBinaryProgram.cpp

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,34 +77,62 @@ std::string CgBinaryDisasm::GetCgParamValue(u32 offset, u32 end_offset) const
7777
return fmt::format("num %d ", num) + offsets;
7878
}
7979

80-
void CgBinaryDisasm::ConvertToLE(CgBinaryProgram& prog)
80+
bool CgBinaryDisasm::ConvertToLE(CgBinaryProgram& prog)
8181
{
8282
// BE payload, requires that data be swapped
8383
const auto be_profile = prog.profile;
8484

8585
auto swap_be32 = [&](u32 start_offset, size_t size_bytes)
8686
{
87+
if (static_cast<usz>(start_offset) > m_buffer.size()
88+
|| size_bytes > m_buffer.size() - start_offset
89+
|| start_offset % alignof(u32)
90+
|| size_bytes % sizeof(u32))
91+
{
92+
return false;
93+
}
94+
8795
auto start = reinterpret_cast<u32*>(m_buffer.data() + start_offset);
8896
auto end = reinterpret_cast<u32*>(m_buffer.data() + start_offset + size_bytes);
8997

9098
for (auto data = start; data < end; ++data)
9199
{
92100
*data = std::bit_cast<be_t<u32>>(*data);
93101
}
102+
103+
return true;
94104
};
95105

96106
// 1. Swap the header
97-
swap_be32(0, sizeof(CgBinaryProgram));
107+
if (!swap_be32(0, sizeof(CgBinaryProgram)))
108+
{
109+
return false;
110+
}
98111

99112
// 2. Swap parameters
100-
swap_be32(prog.parameterArray, sizeof(CgBinaryParameter) * prog.parameterCount);
113+
if (static_cast<usz>(prog.parameterCount) > static_cast<usz>(umax) / sizeof(CgBinaryParameter)
114+
|| !swap_be32(prog.parameterArray, sizeof(CgBinaryParameter) * prog.parameterCount))
115+
{
116+
return false;
117+
}
101118

102119
// 3. Swap the ucode
103-
swap_be32(prog.ucode, m_buffer.size() - prog.ucode);
120+
if (static_cast<usz>(prog.ucode) > m_buffer.size()
121+
|| !swap_be32(prog.ucode, m_buffer.size() - prog.ucode))
122+
{
123+
return false;
124+
}
104125

105126
// 4. Swap the domain header
106127
if (be_profile == 7004u)
107128
{
129+
if (static_cast<usz>(prog.program) > m_buffer.size()
130+
|| sizeof(CgBinaryFragmentProgram) > m_buffer.size() - prog.program
131+
|| prog.program % alignof(u32))
132+
{
133+
return false;
134+
}
135+
108136
// Need to swap each field individually
109137
auto& fprog = GetCgRef<CgBinaryFragmentProgram>(prog.program);
110138
fprog.instructionCount = std::bit_cast<be_t<u32>>(fprog.instructionCount);
@@ -117,20 +145,34 @@ void CgBinaryDisasm::ConvertToLE(CgBinaryProgram& prog)
117145
else
118146
{
119147
// Swap entire header block as all fields are u32
120-
swap_be32(prog.program, sizeof(CgBinaryVertexProgram));
148+
if (!swap_be32(prog.program, sizeof(CgBinaryVertexProgram)))
149+
{
150+
return false;
151+
}
121152
}
153+
154+
return true;
122155
}
123156

124157
void CgBinaryDisasm::BuildShaderBody(bool include_glsl)
125158
{
126159
ParamArray param_array;
127160

161+
if (m_buffer.size() < sizeof(CgBinaryProgram))
162+
{
163+
return;
164+
}
165+
128166
auto& prog = GetCgRef<CgBinaryProgram>(0);
129167

130168
if (const u32 be_profile = std::bit_cast<be_t<u32>>(prog.profile);
131169
be_profile == 7003u || be_profile == 7004u)
132170
{
133-
ConvertToLE(prog);
171+
if (!ConvertToLE(prog))
172+
{
173+
return;
174+
}
175+
134176
ensure(be_profile == prog.profile);
135177
}
136178

rpcs3/Emu/RSX/Program/CgBinaryProgram.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ class CgBinaryDisasm
208208
std::string GetCgParamSemantic(u32 offset) const;
209209
std::string GetCgParamValue(u32 offset, u32 end_offset) const;
210210

211-
void ConvertToLE(CgBinaryProgram& prog);
211+
bool ConvertToLE(CgBinaryProgram& prog);
212212
void BuildShaderBody(bool include_glsl = true);
213213

214214
static u32 GetData(const u32 d) { return d << 16 | d >> 16; }

0 commit comments

Comments
 (0)