Check that there is enough room to write a patch when linking

Prevents segfaulting if a patch's offset is too large
This commit is contained in:
ISSOtm
2024-08-23 00:49:42 +02:00
committed by Sylvie
parent fbe28e0def
commit 8286d9c462

View File

@@ -465,8 +465,28 @@ static void applyFilePatches(Section &section, Section &dataSection) {
int32_t value = computeRPNExpr(patch, *section.fileSymbols); int32_t value = computeRPNExpr(patch, *section.fileSymbols);
uint16_t offset = patch.offset + section.offset; uint16_t offset = patch.offset + section.offset;
// `jr` is quite unlike the others... struct {
if (patch.type == PATCHTYPE_JR) { uint8_t size;
int32_t min;
int32_t max;
} const types[PATCHTYPE_INVALID] = {
{1, -128, 255 }, // PATCHTYPE_BYTE
{2, -32768, 65536 }, // PATCHTYPE_WORD
{4, INT32_MIN, INT32_MAX}, // PATCHTYPE_LONG
{1, 0, 0 }, // PATCHTYPE_JR
};
auto const &type = types[patch.type];
if (dataSection.data.size() < offset + type.size) {
error(
patch.src,
patch.lineNo,
"Patch would write %zu bytes past the end of section \"%s\" (%zu bytes long)",
offset + type.size - dataSection.data.size(),
dataSection.name.c_str(),
dataSection.data.size()
);
} else if (patch.type == PATCHTYPE_JR) { // `jr` is quite unlike the others...
// Offset is relative to the byte *after* the operand // Offset is relative to the byte *after* the operand
// PC as operand to `jr` is lower than reference PC by 2 // PC as operand to `jr` is lower than reference PC by 2
uint16_t address = patch.pcSection->org + patch.pcOffset + 2; uint16_t address = patch.pcSection->org + patch.pcOffset + 2;
@@ -483,26 +503,16 @@ static void applyFilePatches(Section &section, Section &dataSection) {
dataSection.data[offset] = jumpOffset & 0xFF; dataSection.data[offset] = jumpOffset & 0xFF;
} else { } else {
// Patch a certain number of bytes // Patch a certain number of bytes
struct { if (!isError && (value < type.min || value > type.max))
uint8_t size;
int32_t min;
int32_t max;
} const types[PATCHTYPE_INVALID] = {
{1, -128, 255 }, // PATCHTYPE_BYTE
{2, -32768, 65536 }, // PATCHTYPE_WORD
{4, INT32_MIN, INT32_MAX}, // PATCHTYPE_LONG
};
if (!isError && (value < types[patch.type].min || value > types[patch.type].max))
error( error(
patch.src, patch.src,
patch.lineNo, patch.lineNo,
"Value %" PRId32 "%s is not %u-bit", "Value %" PRId32 "%s is not %u-bit",
value, value,
value < 0 ? " (maybe negative?)" : "", value < 0 ? " (maybe negative?)" : "",
types[patch.type].size * 8U type.size * 8U
); );
for (uint8_t i = 0; i < types[patch.type].size; i++) { for (uint8_t i = 0; i < type.size; i++) {
dataSection.data[offset + i] = value & 0xFF; dataSection.data[offset + i] = value & 0xFF;
value >>= 8; value >>= 8;
} }