Add memory management improvements and validation checks in aaruf_get_dumphw and aaruf_set_dumphw functions

This commit is contained in:
2025-10-08 19:41:11 +01:00
parent 709543a37d
commit 8162a6f6cb

View File

@@ -23,6 +23,26 @@
#include "internal.h"
#include "log.h"
static void free_dump_hardware_entries(DumpHardwareEntriesWithData *entries, uint32_t count)
{
if(entries == NULL) return;
for(uint32_t e = 0; e < count; e++)
{
free(entries[e].manufacturer);
free(entries[e].model);
free(entries[e].revision);
free(entries[e].firmware);
free(entries[e].serial);
free(entries[e].softwareName);
free(entries[e].softwareVersion);
free(entries[e].softwareOperatingSystem);
free(entries[e].extents);
}
free(entries);
}
/**
* @brief Retrieves the dump hardware block containing acquisition environment information.
*
@@ -165,7 +185,10 @@
*/
int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
{
TRACE("Entering aaruf_get_dumphw(%p, %p, %u)", context, buffer, *length);
size_t length_value = 0;
if(length != NULL) length_value = *length;
TRACE("Entering aaruf_get_dumphw(%p, %p, %zu)", context, buffer, length_value);
aaruformatContext *ctx = NULL;
@@ -177,6 +200,14 @@ int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(length == NULL)
{
FATAL("Invalid length pointer");
TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
ctx = context;
// Not a libaaruformat context
@@ -197,7 +228,14 @@ int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
return AARUF_ERROR_CANNOT_READ_BLOCK;
}
size_t required_length = sizeof(DumpHardwareHeader) + ctx->dumpHardwareHeader.length;
size_t required_length = sizeof(DumpHardwareHeader) + (size_t)ctx->dumpHardwareHeader.length;
if(required_length < sizeof(DumpHardwareHeader))
{
FATAL("Dump hardware payload length overflow");
TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(buffer == NULL || *length < required_length)
{
@@ -212,17 +250,40 @@ int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
// Start to iterate and copy the data
size_t offset = 0;
for(int i = 0; i < ctx->dumpHardwareHeader.entries; i++)
for(uint32_t i = 0; i < ctx->dumpHardwareHeader.entries; i++)
{
size_t entry_size = sizeof(DumpHardwareEntry) + ctx->dumpHardwareEntriesWithData[i].entry.manufacturerLength +
ctx->dumpHardwareEntriesWithData[i].entry.modelLength +
ctx->dumpHardwareEntriesWithData[i].entry.revisionLength +
ctx->dumpHardwareEntriesWithData[i].entry.firmwareLength +
ctx->dumpHardwareEntriesWithData[i].entry.serialLength +
ctx->dumpHardwareEntriesWithData[i].entry.softwareNameLength +
ctx->dumpHardwareEntriesWithData[i].entry.softwareVersionLength +
ctx->dumpHardwareEntriesWithData[i].entry.softwareOperatingSystemLength +
ctx->dumpHardwareEntriesWithData[i].entry.extents * sizeof(DumpExtent);
size_t entry_size = sizeof(DumpHardwareEntry);
const DumpHardwareEntry *entry = &ctx->dumpHardwareEntriesWithData[i].entry;
const size_t extent_bytes = (size_t)entry->extents * sizeof(DumpExtent);
if(entry->extents != 0 && extent_bytes / sizeof(DumpExtent) != entry->extents)
{
FATAL("Dump hardware extent size overflow");
TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
const size_t additive_lengths[] = {entry->manufacturerLength,
entry->modelLength,
entry->revisionLength,
entry->firmwareLength,
entry->serialLength,
entry->softwareNameLength,
entry->softwareVersionLength,
entry->softwareOperatingSystemLength,
extent_bytes};
for(size_t j = 0; j < sizeof(additive_lengths) / sizeof(additive_lengths[0]); j++)
{
if(additive_lengths[j] > SIZE_MAX - entry_size)
{
FATAL("Dump hardware entry size overflow");
TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
entry_size += additive_lengths[j];
}
if(offset + entry_size > *length)
{
@@ -289,11 +350,10 @@ int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
ctx->dumpHardwareEntriesWithData[i].entry.softwareOperatingSystemLength);
offset += ctx->dumpHardwareEntriesWithData[i].entry.softwareOperatingSystemLength;
}
if(ctx->dumpHardwareEntriesWithData[i].entry.extents > 0 && ctx->dumpHardwareEntriesWithData[i].extents != NULL)
if(entry->extents > 0 && ctx->dumpHardwareEntriesWithData[i].extents != NULL)
{
memcpy(buffer + offset, ctx->dumpHardwareEntriesWithData[i].extents,
ctx->dumpHardwareEntriesWithData[i].entry.extents * sizeof(DumpExtent));
offset += ctx->dumpHardwareEntriesWithData[i].entry.extents * sizeof(DumpExtent);
memcpy(buffer + offset, ctx->dumpHardwareEntriesWithData[i].extents, extent_bytes);
offset += extent_bytes;
}
}
@@ -439,7 +499,6 @@ int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
* - Extents indicate which sectors this environment contributed
* - Empty extent arrays (extents == 0) mean the environment dumped entire medium
* - Extents are stored in the order provided in the input buffer
* - TODO note in code indicates extents should be sorted (qsort) but not implemented
*
* @note Memory Ownership:
* - The function creates internal copies of all data
@@ -505,6 +564,16 @@ int32_t aaruf_set_dumphw(void *context, uint8_t *data, size_t length)
if(data == NULL || length == 0)
{
FATAL("Invalid data or length");
TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(length < sizeof(DumpHardwareHeader))
{
FATAL("Dump hardware block shorter than header");
TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
@@ -535,192 +604,91 @@ int32_t aaruf_set_dumphw(void *context, uint8_t *data, size_t length)
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
// Allocate copy buffer
DumpHardwareEntriesWithData *copy = calloc(1, sizeof(DumpHardwareEntriesWithData) * header.entries);
if(copy == NULL)
DumpHardwareEntriesWithData *copy = NULL;
if(header.entries > 0)
{
TRACE("Could not allocate memory for dump hardware block...");
TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
copy = calloc(header.entries, sizeof(DumpHardwareEntriesWithData));
if(copy == NULL)
{
TRACE("Could not allocate memory for dump hardware block entries");
TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
}
TRACE("Processing %u dump hardware block entries", header.entries);
int pos = sizeof(DumpHardwareHeader);
size_t pos = sizeof(DumpHardwareHeader);
for(int e = 0; e < ctx->dumpHardwareHeader.entries; e++)
#define COPY_STRING_FIELD(field) \
do { \
const size_t field##_length = copy[e].entry.field##Length; \
if(field##_length > 0) \
{ \
if(field##_length > length - pos) goto invalid_data; \
copy[e].field = (uint8_t *)calloc(1, field##_length + 1); \
if(copy[e].field == NULL) goto free_copy_and_error; \
memcpy(copy[e].field, data + pos, field##_length); \
pos += field##_length; \
} \
} while(0)
for(uint32_t e = 0; e < header.entries; e++)
{
if(length - pos < sizeof(DumpHardwareEntry)) goto invalid_data;
memcpy(&copy[e].entry, data + pos, sizeof(DumpHardwareEntry));
pos += sizeof(DumpHardwareEntry);
if(copy[e].entry.manufacturerLength > 0)
COPY_STRING_FIELD(manufacturer);
COPY_STRING_FIELD(model);
COPY_STRING_FIELD(revision);
COPY_STRING_FIELD(firmware);
COPY_STRING_FIELD(serial);
COPY_STRING_FIELD(softwareName);
COPY_STRING_FIELD(softwareVersion);
COPY_STRING_FIELD(softwareOperatingSystem);
const uint32_t extent_count = copy[e].entry.extents;
if(extent_count > 0)
{
copy[e].manufacturer = (uint8_t *)calloc(1, copy[e].entry.manufacturerLength + 1);
const size_t extent_bytes = (size_t)extent_count * sizeof(DumpExtent);
if(extent_bytes / sizeof(DumpExtent) != extent_count || extent_bytes > length - pos) goto invalid_data;
if(copy[e].manufacturer == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry manufacturer");
goto free_copy_and_error;
}
copy[e].extents = (DumpExtent *)malloc(extent_bytes);
if(copy[e].extents == NULL) goto free_copy_and_error;
memcpy(copy[e].manufacturer, data + pos, copy[e].entry.manufacturerLength);
pos += copy[e].entry.manufacturerLength;
}
memcpy(copy[e].extents, data + pos, extent_bytes);
pos += extent_bytes;
if(copy[e].entry.modelLength > 0)
{
copy[e].model = (uint8_t *)calloc(1, copy[e].entry.modelLength + 1);
if(copy[e].model == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry model");
goto free_copy_and_error;
}
memcpy(copy[e].manufacturer, data + pos, copy[e].entry.modelLength);
pos += copy[e].entry.modelLength;
}
if(copy[e].entry.revisionLength > 0)
{
copy[e].revision = (uint8_t *)calloc(1, copy[e].entry.revisionLength + 1);
if(copy[e].revision == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry revision");
goto free_copy_and_error;
}
memcpy(copy[e].revision, data + pos, copy[e].entry.revisionLength);
pos += copy[e].entry.revisionLength;
}
if(copy[e].entry.firmwareLength > 0)
{
copy[e].firmware = (uint8_t *)calloc(1, copy[e].entry.firmwareLength + 1);
if(copy[e].firmware == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry firmware");
goto free_copy_and_error;
}
memcpy(copy[e].firmware, data + pos, copy[e].entry.firmwareLength);
pos += copy[e].entry.firmwareLength;
}
if(copy[e].entry.serialLength > 0)
{
copy[e].serial = (uint8_t *)calloc(1, copy[e].entry.serialLength + 1);
if(copy[e].serial == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry serial");
goto free_copy_and_error;
}
memcpy(copy[e].serial, data + pos, copy[e].entry.serialLength);
pos += copy[e].entry.serialLength;
}
if(copy[e].entry.softwareNameLength > 0)
{
copy[e].softwareName = (uint8_t *)calloc(1, copy[e].entry.softwareNameLength + 1);
if(copy[e].softwareName == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry software name");
goto free_copy_and_error;
}
memcpy(copy[e].softwareName, data + pos, copy[e].entry.softwareNameLength);
pos += copy[e].entry.softwareNameLength;
}
if(copy[e].entry.softwareVersionLength > 0)
{
copy[e].softwareVersion = (uint8_t *)calloc(1, copy[e].entry.softwareVersionLength + 1);
if(copy[e].softwareVersion == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry software version");
goto free_copy_and_error;
}
memcpy(copy[e].softwareVersion, data + pos, copy[e].entry.softwareVersionLength);
pos += copy[e].entry.softwareVersionLength;
}
if(copy[e].entry.softwareOperatingSystemLength > 0)
{
copy[e].softwareOperatingSystem = (uint8_t *)calloc(1, copy[e].entry.softwareOperatingSystemLength + 1);
if(copy[e].softwareOperatingSystem == NULL)
{
TRACE("Could not allocate memory for dump hardware block entry software operating system");
goto free_copy_and_error;
}
memcpy(copy[e].softwareOperatingSystem, data + pos, copy[e].entry.softwareOperatingSystemLength);
pos += copy[e].entry.softwareOperatingSystemLength;
}
copy[e].extents = (DumpExtent *)malloc(sizeof(DumpExtent) * ctx->dumpHardwareEntriesWithData->entry.extents);
if(copy[e].extents == NULL)
{
TRACE("Could not allocate memory for dump hardware block extents");
goto free_copy_and_error;
}
memcpy(copy[e].extents, data + pos, sizeof(DumpExtent) * ctx->dumpHardwareEntriesWithData->entry.extents);
pos += sizeof(DumpExtent) * ctx->dumpHardwareEntriesWithData->entry.extents;
// Sort extents by start sector for efficient lookup and validation
if(copy[e].entry.extents > 0 && copy[e].extents != NULL)
{
qsort(copy[e].extents, copy[e].entry.extents, sizeof(DumpExtent), compare_extents);
TRACE("Sorted %u extents for entry %d", copy[e].entry.extents, e);
qsort(copy[e].extents, extent_count, sizeof(DumpExtent), compare_extents);
TRACE("Sorted %u extents for entry %u", extent_count, e);
}
}
// Free old data
for(int e = 0; e < ctx->dumpHardwareHeader.entries; e++)
#undef COPY_STRING_FIELD
if(pos != length)
{
free(ctx->dumpHardwareEntriesWithData[e].manufacturer);
free(ctx->dumpHardwareEntriesWithData[e].model);
free(ctx->dumpHardwareEntriesWithData[e].revision);
free(ctx->dumpHardwareEntriesWithData[e].firmware);
free(ctx->dumpHardwareEntriesWithData[e].serial);
free(ctx->dumpHardwareEntriesWithData[e].softwareName);
free(ctx->dumpHardwareEntriesWithData[e].softwareVersion);
free(ctx->dumpHardwareEntriesWithData[e].softwareOperatingSystem);
free(ctx->dumpHardwareEntriesWithData[e].extents);
FATAL("Dump hardware block contains trailing data");
goto invalid_data;
}
free(ctx->dumpHardwareEntriesWithData);
free_dump_hardware_entries(ctx->dumpHardwareEntriesWithData, ctx->dumpHardwareHeader.entries);
ctx->dumpHardwareEntriesWithData = copy;
ctx->dumpHardwareHeader = header;
TRACE("Exiting aaruf_set_dumphw() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
// Free copy and return not enough memory error
invalid_data:
TRACE("Dump hardware block truncated or malformed");
free_dump_hardware_entries(copy, header.entries);
TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
free_copy_and_error:
for(int e = 0; e < header.entries; e++)
{
free(copy[e].manufacturer);
free(copy[e].model);
free(copy[e].revision);
free(copy[e].firmware);
free(copy[e].serial);
free(copy[e].softwareName);
free(copy[e].softwareVersion);
free(copy[e].softwareOperatingSystem);
free(copy[e].extents);
}
free(copy);
free_dump_hardware_entries(copy, header.entries);
TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}