diff --git a/clamonacc/inotif/inotif.c b/clamonacc/inotif/inotif.c index bb25363e98..74654b19a0 100644 --- a/clamonacc/inotif/inotif.c +++ b/clamonacc/inotif/inotif.c @@ -143,6 +143,7 @@ int onas_ddd_init(uint64_t nwatches, size_t ht_size) int ret = 0; char nwatch_str[MAX_WATCH_LEN + 1] = {0}; char *p = NULL; + int64_t tmp = 0; nwatches = 0; nwfd = open(nwatch_file, O_RDONLY); @@ -152,7 +153,13 @@ int onas_ddd_init(uint64_t nwatches, size_t ht_size) close(nwfd); if (ret < 0) return CL_EREAD; - nwatches = strtol(nwatch_str, &p, 10); + tmp = strtol(nwatch_str, &p, 10); + if (tmp < 0 || tmp == LONG_MAX){ + /*Seems like a sane value (also the value on my ubuntu system)*/ + nwatches = 0x10000; + } else { + nwatches = tmp; + } ret = onas_ddd_init_wdlt(nwatches); if (ret) return ret; diff --git a/libclamav/scanners.c b/libclamav/scanners.c index 832f0dc670..1b83a13f2b 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -388,7 +388,7 @@ static cl_error_t cli_scanrar_file(const char *filepath, int desc, cli_ctx *ctx) /* * Extract the file... */ - if (NULL != metadata.filename) { + if (0 != metadata.filename[0]) { (void)cli_basename(metadata.filename, strlen(metadata.filename), &filename_base); } diff --git a/libclamav/udf.c b/libclamav/udf.c index 14a1c0a88b..0cda95dbae 100644 --- a/libclamav/udf.c +++ b/libclamav/udf.c @@ -29,6 +29,7 @@ #include "hashtab.h" typedef enum { + INVALID_DESCRIPTOR = 0, PRIMARY_VOLUME_DESCRIPTOR = 1, IMPLEMENTATION_USE_VOLUME_DESCRIPTOR = 4, LOGICAL_VOLUME_DESCRIPTOR = 6, @@ -36,17 +37,16 @@ typedef enum { UNALLOCATED_SPACE_DESCRIPTOR = 7, TERMINATING_DESCRIPTOR = 8, LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR = 9, - ANCHOR_VOLUME_DESCRIPTOR_DESCRIPTOR_POINTER = 2 - - , - FILE_SET_DESCRIPTOR = 256, - FILE_IDENTIFIER_DESCRIPTOR = 257, - FILE_ENTRY_DESCRIPTOR = 261 -} VOLUME_DESCRIPTOR_TAG; - -static uint16_t getDescriptorTagId(const uint8_t *const buffer) + ANCHOR_VOLUME_DESCRIPTOR_DESCRIPTOR_POINTER = 2, + FILE_SET_DESCRIPTOR = 256, + FILE_IDENTIFIER_DESCRIPTOR = 257, + FILE_ENTRY_DESCRIPTOR = 261, + EXTENDED_FILE_ENTRY_DESCRIPTOR = 266 +} tag_identifier; + +static tag_identifier getDescriptorTagId(DescriptorTag *tag) { - return le16_to_host(((DescriptorTag *)buffer)->tagId); + return le16_to_host(tag->tagId); } static bool isDirectory(FileIdentifierDescriptor *fid) @@ -56,7 +56,6 @@ static bool isDirectory(FileIdentifierDescriptor *fid) static cl_error_t writeWholeFile(cli_ctx *ctx, const char *const fileName, const uint8_t *const data, const size_t dataLen) { - int fd = -1; char *tmpf = NULL; @@ -105,58 +104,76 @@ static cl_error_t writeWholeFile(cli_ctx *ctx, const char *const fileName, const return status; } -static cl_error_t extractFile(cli_ctx *ctx, PartitionDescriptor *pPartitionDescriptor, LogicalVolumeDescriptor *pLogicalVolumeDescriptor, void *address, uint16_t icbFlags, FileIdentifierDescriptor *fileIdentifierDescriptor) +static cl_error_t extractFile(cli_ctx *ctx, PartitionDescriptor *pPartitionDescriptor, LogicalVolumeDescriptor *pLogicalVolumeDescriptor, + void *allocation_descriptor, + size_t allocation_descriptor_len, + uint16_t icbFlags, FileIdentifierDescriptor *fileIdentifierDescriptor) { - - cl_error_t ret = CL_SUCCESS; - uint32_t offset = 0; - uint32_t length = 0; - uint8_t *contents = NULL; + cl_error_t ret = CL_EPARSE; + uint32_t offset = 0; + uint32_t length = 0; + uint8_t *contents = NULL; + uint32_t partitionStartingLocation = le32_to_host(pPartitionDescriptor->partitionStartingLocation); + uint32_t logicalBlockSize = le32_to_host(pLogicalVolumeDescriptor->logicalBlockSize); if (isDirectory(fileIdentifierDescriptor)) { + cli_dbgmsg("extractFile: Skipping directory\n"); + ret = CL_SUCCESS; goto done; } switch (icbFlags & 3) { case 0: { - short_ad *shortDesc = (short_ad *)address; + if (sizeof(short_ad) != allocation_descriptor_len) { + cli_warnmsg("extractFile: Short Allocation Descriptor length is incorrect.\n"); + goto done; + } - offset = pPartitionDescriptor->partitionStartingLocation * pLogicalVolumeDescriptor->logicalBlockSize; - offset += shortDesc->position * pLogicalVolumeDescriptor->logicalBlockSize; + short_ad *shortDesc = (short_ad *)allocation_descriptor; - length = shortDesc->length; + offset = partitionStartingLocation * logicalBlockSize; + offset += le32_to_host(shortDesc->position) * logicalBlockSize; + + length = le32_to_host(shortDesc->length); } break; case 1: { - long_ad *longDesc = (long_ad *)address; - offset = pPartitionDescriptor->partitionStartingLocation * pLogicalVolumeDescriptor->logicalBlockSize; - length = longDesc->length; + if (sizeof(long_ad) != allocation_descriptor_len) { + cli_warnmsg("extractFile: Long Allocation Descriptor length is incorrect.\n"); + goto done; + } + + long_ad *longDesc = (long_ad *)allocation_descriptor; + + offset = partitionStartingLocation * logicalBlockSize; + length = le32_to_host(longDesc->length); - if (longDesc->extentLocation.partitionReferenceNumber != pPartitionDescriptor->partitionNumber) { + if (le16_to_host(longDesc->extentLocation.partitionReferenceNumber) != le16_to_host(pPartitionDescriptor->partitionNumber)) { cli_warnmsg("extractFile: Unable to extract the files because the Partition Descriptor Reference Numbers don't match\n"); goto done; } - offset += longDesc->extentLocation.blockNumber * pLogicalVolumeDescriptor->logicalBlockSize; - offset += pPartitionDescriptor->partitionStartingLocation; + offset += le32_to_host(longDesc->extentLocation.blockNumber) * logicalBlockSize; + offset += partitionStartingLocation; } break; - case 2: + case 2: { + if (sizeof(ext_ad) != allocation_descriptor_len) { + cli_warnmsg("extractFile: Extended Allocation Descriptor length is incorrect.\n"); + goto done; + } - { - ext_ad *extDesc = (ext_ad *)address; - offset = pPartitionDescriptor->partitionStartingLocation * pLogicalVolumeDescriptor->logicalBlockSize; - length = extDesc->recordedLen; + ext_ad *extDesc = (ext_ad *)allocation_descriptor; - if (extDesc->extentLocation.partitionReferenceNumber != pPartitionDescriptor->partitionNumber) { + offset = partitionStartingLocation * logicalBlockSize; + length = le32_to_host(extDesc->recordedLen); + + if (le16_to_host(extDesc->extentLocation.partitionReferenceNumber) != le16_to_host(pPartitionDescriptor->partitionNumber)) { cli_warnmsg("extractFile: Unable to extract the files because the Partition Descriptor Reference Numbers don't match\n"); goto done; } - offset += extDesc->extentLocation.blockNumber * pLogicalVolumeDescriptor->logicalBlockSize; - offset += pPartitionDescriptor->partitionStartingLocation; - - } - - break; + offset += le32_to_host(extDesc->extentLocation.blockNumber) * logicalBlockSize; + offset += partitionStartingLocation; + } break; default: // impossible unless the file is malformed. cli_warnmsg("extractFile: Unknown descriptor type found.\n"); @@ -178,26 +195,49 @@ static cl_error_t extractFile(cli_ctx *ctx, PartitionDescriptor *pPartitionDescr return ret; } -static bool parseFileEntryDescriptor(cli_ctx *ctx, const uint8_t *const data, PartitionDescriptor *pPartitionDescriptor, LogicalVolumeDescriptor *pLogicalVolumeDescriptor, FileIdentifierDescriptor *fileIdentifierDescriptor) +static bool parseFileEntryDescriptor(cli_ctx *ctx, FileEntryDescriptor *fed, PartitionDescriptor *pPartitionDescriptor, LogicalVolumeDescriptor *pLogicalVolumeDescriptor, FileIdentifierDescriptor *fileIdentifierDescriptor) { + bool ret = false; + uint16_t tagId = getDescriptorTagId(&fed->tag); + void *allocation_descriptor = NULL; - FileEntryDescriptor *fed = (FileEntryDescriptor *)data; - bool ret = false; + size_t file_entry_descriptor_size; + size_t allocation_descriptor_len; - if (FILE_ENTRY_DESCRIPTOR != fed->tag.tagId) { - cli_warnmsg("parseFileEntryDescriptor: Tag ID of 0x%x does not match File Entry Descriptor.\n", fed->tag.tagId); + if (FILE_ENTRY_DESCRIPTOR != tagId) { + cli_warnmsg("parseFileEntryDescriptor: Tag ID of 0x%x does not match File Entry Descriptor.\n", tagId); goto done; } - if (FILE_IDENTIFIER_DESCRIPTOR != fileIdentifierDescriptor->tag.tagId) { - cli_warnmsg("parseFileEntryDescriptor: Tag ID of 0x%x does not match File Identifier Descriptor.\n", fed->tag.tagId); + tagId = getDescriptorTagId(&fileIdentifierDescriptor->tag); + if (FILE_IDENTIFIER_DESCRIPTOR != tagId) { + cli_warnmsg("parseFileEntryDescriptor: Tag ID of 0x%x does not match File Identifier Descriptor.\n", tagId); goto done; } + // Calculate pointer for the allocation descriptor. + // The allocation descriptors are the last bytes of the Extended File Entry. + // See Section 14.17 in https://www.ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf + file_entry_descriptor_size = getFileEntryDescriptorSize(fed); + allocation_descriptor_len = le32_to_host(fed->allocationDescLen); + + if (allocation_descriptor_len > file_entry_descriptor_size) { + cli_dbgmsg("parseFileEntryDescriptor: Allocation Descriptor Length is greater than the File Entry Descriptor Size.\n"); + goto done; + } + allocation_descriptor = (void *)((uint8_t *)fed + (file_entry_descriptor_size - allocation_descriptor_len)); + + // The Allocation Descriptor was taken from the end of the File Entry Descriptor. + // We already verified that the File Entry Descriptor is within the fmap, + // so it's safe to say the Allocation Descriptor is also within the fmap. + // No need to use an `fmap_need...()` function here. + + // Extract the file. if (CL_SUCCESS != extractFile(ctx, pPartitionDescriptor, pLogicalVolumeDescriptor, - (void *)&(data[getFileEntryDescriptorSize(fed) - fed->allocationDescLen]), - fed->icbTag.flags, fileIdentifierDescriptor)) { - ret = false; + allocation_descriptor, + allocation_descriptor_len, + le16_to_host(fed->icbTag.flags), fileIdentifierDescriptor)) { + cli_dbgmsg("parseFileEntryDescriptor: Failed to extract file.\n"); goto done; } @@ -221,12 +261,6 @@ static void dumpTag (DescriptorTag *dt) } */ -typedef struct { - uint8_t structType; - char standardIdentifier[5]; - uint8_t structVersion; - uint8_t rest[2041]; -} GenericVolumeStructureDescriptor; #define NUM_GENERIC_VOLUME_DESCRIPTORS 3 /* If this function fails, idx will not be updated */ @@ -239,7 +273,6 @@ static bool skipEmptyDescriptors(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp size_t i; while (1) { - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); if (NULL == buffer) { goto done; @@ -271,7 +304,6 @@ static bool skipEmptyDescriptors(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp * Return error if the next non-empty descriptor is not a PrimaryVolumeDescriptor. */ static PrimaryVolumeDescriptor *getPrimaryVolumeDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; PrimaryVolumeDescriptor *test = NULL; PrimaryVolumeDescriptor *ret = NULL; size_t idx = *idxp; @@ -284,14 +316,13 @@ static PrimaryVolumeDescriptor *getPrimaryVolumeDescriptor(cli_ctx *ctx, size_t idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (PrimaryVolumeDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (PrimaryVolumeDescriptor *)buffer; - if (PRIMARY_VOLUME_DESCRIPTOR != test->tag.tagId) { + if (PRIMARY_VOLUME_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -309,7 +340,6 @@ static PrimaryVolumeDescriptor *getPrimaryVolumeDescriptor(cli_ctx *ctx, size_t * Return error if the next non-empty descriptor is not an ImplementationUseVolumeDescriptor. */ static ImplementationUseVolumeDescriptor *getImplementationUseVolumeDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; ImplementationUseVolumeDescriptor *test = NULL; ImplementationUseVolumeDescriptor *ret = NULL; size_t idx = *idxp; @@ -322,14 +352,13 @@ static ImplementationUseVolumeDescriptor *getImplementationUseVolumeDescriptor(c idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (ImplementationUseVolumeDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (ImplementationUseVolumeDescriptor *)buffer; - if (IMPLEMENTATION_USE_VOLUME_DESCRIPTOR != test->tag.tagId) { + if (IMPLEMENTATION_USE_VOLUME_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -347,7 +376,6 @@ static ImplementationUseVolumeDescriptor *getImplementationUseVolumeDescriptor(c * Return error if the next non-empty descriptor is not a LogicalVolumeDescriptor. */ static LogicalVolumeDescriptor *getLogicalVolumeDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; LogicalVolumeDescriptor *ret = NULL; LogicalVolumeDescriptor *test = NULL; size_t idx = *idxp; @@ -360,14 +388,13 @@ static LogicalVolumeDescriptor *getLogicalVolumeDescriptor(cli_ctx *ctx, size_t idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (LogicalVolumeDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (LogicalVolumeDescriptor *)buffer; - if (LOGICAL_VOLUME_DESCRIPTOR != test->tag.tagId) { + if (LOGICAL_VOLUME_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -385,7 +412,6 @@ static LogicalVolumeDescriptor *getLogicalVolumeDescriptor(cli_ctx *ctx, size_t * Return error if the next non-empty descriptor is not a PartitionDescriptor. */ static PartitionDescriptor *getPartitionDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; PartitionDescriptor *ret = NULL; PartitionDescriptor *test = NULL; size_t idx = *idxp; @@ -398,14 +424,13 @@ static PartitionDescriptor *getPartitionDescriptor(cli_ctx *ctx, size_t *idxp, s idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (PartitionDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (PartitionDescriptor *)buffer; - if (PARTITION_DESCRIPTOR != test->tag.tagId) { + if (PARTITION_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -423,7 +448,6 @@ static PartitionDescriptor *getPartitionDescriptor(cli_ctx *ctx, size_t *idxp, s * Return error if the next non-empty descriptor is not a UnallocatedSpaceDescriptor. */ static UnallocatedSpaceDescriptor *getUnallocatedSpaceDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; UnallocatedSpaceDescriptor *ret = NULL; UnallocatedSpaceDescriptor *test = NULL; size_t idx = *idxp; @@ -436,14 +460,13 @@ static UnallocatedSpaceDescriptor *getUnallocatedSpaceDescriptor(cli_ctx *ctx, s idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (UnallocatedSpaceDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (UnallocatedSpaceDescriptor *)buffer; - if (UNALLOCATED_SPACE_DESCRIPTOR != test->tag.tagId) { + if (UNALLOCATED_SPACE_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -461,7 +484,6 @@ static UnallocatedSpaceDescriptor *getUnallocatedSpaceDescriptor(cli_ctx *ctx, s * Return error if the next non-empty descriptor is not a TerminatingDescriptor. */ static TerminatingDescriptor *getTerminatingDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; TerminatingDescriptor *ret = NULL; TerminatingDescriptor *test = NULL; size_t idx = *idxp; @@ -474,14 +496,13 @@ static TerminatingDescriptor *getTerminatingDescriptor(cli_ctx *ctx, size_t *idx idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (TerminatingDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (TerminatingDescriptor *)buffer; - if (TERMINATING_DESCRIPTOR != test->tag.tagId) { + if (TERMINATING_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -499,7 +520,6 @@ static TerminatingDescriptor *getTerminatingDescriptor(cli_ctx *ctx, size_t *idx * Return error if the next non-empty descriptor is not a LogicalVolumeIntegrityDescriptor. */ static LogicalVolumeIntegrityDescriptor *getLogicalVolumeIntegrityDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; LogicalVolumeIntegrityDescriptor *ret = NULL; LogicalVolumeIntegrityDescriptor *test = NULL; size_t idx = *idxp; @@ -512,14 +532,13 @@ static LogicalVolumeIntegrityDescriptor *getLogicalVolumeIntegrityDescriptor(cli idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (LogicalVolumeIntegrityDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (LogicalVolumeIntegrityDescriptor *)buffer; - if (LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR != test->tag.tagId) { + if (LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -537,7 +556,6 @@ static LogicalVolumeIntegrityDescriptor *getLogicalVolumeIntegrityDescriptor(cli * Return error if the next non-empty descriptor is not an AnchorVolumeDescriptor. */ static AnchorVolumeDescriptorPointer *getAnchorVolumeDescriptorPointer(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; AnchorVolumeDescriptorPointer *ret = NULL; AnchorVolumeDescriptorPointer *test = NULL; size_t idx = *idxp; @@ -550,19 +568,17 @@ static AnchorVolumeDescriptorPointer *getAnchorVolumeDescriptorPointer(cli_ctx * idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (AnchorVolumeDescriptorPointer *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (AnchorVolumeDescriptorPointer *)buffer; - if (ANCHOR_VOLUME_DESCRIPTOR_DESCRIPTOR_POINTER != test->tag.tagId) { + if (ANCHOR_VOLUME_DESCRIPTOR_DESCRIPTOR_POINTER != getDescriptorTagId(&test->tag)) { goto done; } ret = test; - idx += VOLUME_DESCRIPTOR_SIZE; done: @@ -576,7 +592,6 @@ static AnchorVolumeDescriptorPointer *getAnchorVolumeDescriptorPointer(cli_ctx * * Return error if the next non-empty descriptor is not a FileSetDescriptor. */ static FileSetDescriptor *getFileSetDescriptor(cli_ctx *ctx, size_t *idxp, size_t *lastOffsetp) { - uint8_t *buffer = NULL; FileSetDescriptor *ret = NULL; FileSetDescriptor *test = NULL; size_t idx = *idxp; @@ -589,14 +604,13 @@ static FileSetDescriptor *getFileSetDescriptor(cli_ctx *ctx, size_t *idxp, size_ idx = *idxp; lastOffset = *lastOffsetp; - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + test = (FileSetDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == test) { goto done; } lastOffset = idx; - test = (FileSetDescriptor *)buffer; - if (FILE_SET_DESCRIPTOR != test->tag.tagId) { + if (FILE_SET_DESCRIPTOR != getDescriptorTagId(&test->tag)) { goto done; } @@ -663,18 +677,30 @@ static cl_error_t insertPointer(PointerList *pl, const uint8_t *pointer) static cl_error_t findFileIdentifiers(const uint8_t *const input, PointerList *pfil) { - cl_error_t ret = CL_SUCCESS; const uint8_t *buffer = input; - uint16_t tagId = getDescriptorTagId(buffer); + uint16_t tagId = getDescriptorTagId((DescriptorTag *)buffer); + size_t bufUsed; + size_t fidDescSize; while (FILE_IDENTIFIER_DESCRIPTOR == tagId) { + + /*Check that it's safe to read the header. */ if (CL_SUCCESS != (ret = insertPointer(pfil, buffer))) { goto done; } - buffer = buffer + getFileIdentifierDescriptorSize((FileIdentifierDescriptor *)buffer); - tagId = getDescriptorTagId(buffer); + /*This is how far into the Volume we already are.*/ + bufUsed = buffer - input; + fidDescSize = getFileIdentifierDescriptorSize((FileIdentifierDescriptor *)buffer); + + /* Check that it's safe to read the header for the next FileIdentifierDescriptor */ + if (VOLUME_DESCRIPTOR_SIZE < (fidDescSize + bufUsed + FILE_IDENTIFIER_DESCRIPTOR_SIZE_KNOWN)) { + break; + } + + buffer = buffer + fidDescSize; + tagId = getDescriptorTagId((DescriptorTag *)buffer); } done: @@ -683,18 +709,28 @@ static cl_error_t findFileIdentifiers(const uint8_t *const input, PointerList *p static cl_error_t findFileEntries(const uint8_t *const input, PointerList *pfil) { - cl_error_t ret = CL_SUCCESS; const uint8_t *buffer = input; - uint16_t tagId = getDescriptorTagId(buffer); + uint16_t tagId = getDescriptorTagId((DescriptorTag *)buffer); + size_t bufUsed; + size_t fedDescSize; while (FILE_ENTRY_DESCRIPTOR == tagId) { if (CL_SUCCESS != (ret = insertPointer(pfil, buffer))) { goto done; } - buffer = buffer + getFileEntryDescriptorSize((FileEntryDescriptor *)buffer); - tagId = getDescriptorTagId(buffer); + /*This is how far into the Volume we already are.*/ + bufUsed = buffer - input; + fedDescSize = getFileEntryDescriptorSize((FileEntryDescriptor *)buffer); + + /* Check that it's safe to read the header for the next FileEntryDescriptor */ + if (VOLUME_DESCRIPTOR_SIZE < (fedDescSize + bufUsed + FILE_ENTRY_DESCRIPTOR_SIZE_KNOWN)) { + break; + } + + buffer = buffer + fedDescSize; + tagId = getDescriptorTagId((DescriptorTag *)buffer); } done: @@ -707,7 +743,6 @@ cl_error_t cli_scanudf(cli_ctx *ctx, const size_t offset) size_t idx = offset; size_t lastOffset = 0; size_t i = 0; - uint8_t *buffer = NULL; PrimaryVolumeDescriptor *pvd = NULL; GenericVolumeStructureDescriptor *gvsd = NULL; ImplementationUseVolumeDescriptor *iuvd = NULL; @@ -717,6 +752,8 @@ cl_error_t cli_scanudf(cli_ctx *ctx, const size_t offset) TerminatingDescriptor *td = NULL; LogicalVolumeIntegrityDescriptor *lvid = NULL; AnchorVolumeDescriptorPointer *avdp = NULL; + FileSetDescriptor *fsd = NULL; + DescriptorTag *file_volume_tag = NULL; bool isInitialized = false; PointerList fileIdentifierList = {0}; @@ -726,14 +763,16 @@ cl_error_t cli_scanudf(cli_ctx *ctx, const size_t offset) return CL_SUCCESS; /* Need 16 sectors at least 2048 bytes long */ } - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, NUM_GENERIC_VOLUME_DESCRIPTORS * VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { - ret = CL_SUCCESS; - goto done; - } + cli_dbgmsg("Scanning UDF file\n"); for (i = 0; i < NUM_GENERIC_VOLUME_DESCRIPTORS; i++) { - gvsd = (GenericVolumeStructureDescriptor *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + gvsd = (GenericVolumeStructureDescriptor *)fmap_need_off(ctx->fmap, idx, sizeof(GenericVolumeStructureDescriptor)); + if (NULL == gvsd) { + // File isn't long enough to store the required generic volume structure descriptors at the given offset. + ret = CL_SUCCESS; + goto done; + } + lastOffset = idx; if (strncmp("BEA01", gvsd->standardIdentifier, 5)) { @@ -755,121 +794,187 @@ cl_error_t cli_scanudf(cli_ctx *ctx, const size_t offset) break; } - idx += VOLUME_DESCRIPTOR_SIZE; + fmap_unneed_ptr(ctx->fmap, gvsd, sizeof(GenericVolumeStructureDescriptor)); + + idx += sizeof(GenericVolumeStructureDescriptor); } while (1) { if (!isInitialized) { + /* We don't use most of these descriptors, but verify they all exist because + * they are part of a properly formatted udf file. */ if (CL_SUCCESS != (ret = initPointerList(&fileIdentifierList))) { + cli_dbgmsg("Failed to initialize fileIdentifierList\n"); goto done; } if (CL_SUCCESS != (ret = initPointerList(&fileEntryList))) { + cli_dbgmsg("Failed to initialize fileEntryList\n"); goto done; } if (NULL == (pvd = getPrimaryVolumeDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Primary Volume Descriptor\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, pvd, VOLUME_DESCRIPTOR_SIZE); if (NULL == (iuvd = getImplementationUseVolumeDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Implementation Use Volume Descriptor\n"); goto done; } + // Hold on to this pointer, we'll use it later. + // We'll release it after `done`. if (NULL == (lvd = getLogicalVolumeDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Logical Volume Descriptor\n"); goto done; } + // Hold on to this pointer, we'll use it later. + // We'll release it after `done`. if (NULL == (pd = getPartitionDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Partition Descriptor\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, pd, VOLUME_DESCRIPTOR_SIZE); if (NULL == (usd = getUnallocatedSpaceDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Unallocated Space Descriptor\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, usd, VOLUME_DESCRIPTOR_SIZE); if (NULL == (td = getTerminatingDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Terminating Descriptor\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, td, VOLUME_DESCRIPTOR_SIZE); - /* May not be every file, need to verify. */ if (NULL == (lvid = getLogicalVolumeIntegrityDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Logical Volume Integrity Descriptor\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, lvid, VOLUME_DESCRIPTOR_SIZE); if (NULL == (td = getTerminatingDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Terminating Descriptor\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, td, VOLUME_DESCRIPTOR_SIZE); if (NULL == (avdp = getAnchorVolumeDescriptorPointer(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get Anchor Volume Descriptor Pointer\n"); goto done; } + fmap_unneed_ptr(ctx->fmap, avdp, VOLUME_DESCRIPTOR_SIZE); - if (NULL == getFileSetDescriptor(ctx, &idx, &lastOffset)) { - /*We don't actually use the FileSetDescriptor, but verify it is there because - * that is part of a properly formatted udf file.*/ - goto done; + if (NULL == (fsd = getFileSetDescriptor(ctx, &idx, &lastOffset))) { + cli_dbgmsg("Failed to get File Set Descriptor\n"); + + // The file set descriptor may come after an extended file entry descriptor. + idx = lastOffset; + } else { + fmap_unneed_ptr(ctx->fmap, fsd, VOLUME_DESCRIPTOR_SIZE); } isInitialized = true; } - buffer = (uint8_t *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); - if (NULL == buffer) { + /* + * Find all of the file identifier descriptors and file entry descriptors. + */ + + // Need the entire volume descriptor. We'll un-need it at the end. + file_volume_tag = (DescriptorTag *)fmap_need_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL == file_volume_tag) { + cli_dbgmsg("Failed to get File Volume Tag\n"); goto done; } lastOffset = idx; - uint16_t tagId = getDescriptorTagId(buffer); - if (tagId) { - switch (tagId) { - case FILE_IDENTIFIER_DESCRIPTOR: { - cl_error_t temp = findFileIdentifiers(buffer, &fileIdentifierList); - if (CL_SUCCESS != temp) { - ret = temp; - goto done; - } - break; + tag_identifier tagId = getDescriptorTagId(file_volume_tag); + + cli_dbgmsg("UDF Descriptor Tag ID: %d\n", tagId); + + switch (tagId) { + case FILE_IDENTIFIER_DESCRIPTOR: { + cl_error_t temp = findFileIdentifiers((const uint8_t *)file_volume_tag, &fileIdentifierList); + if (CL_SUCCESS != temp) { + ret = temp; + goto done; } + break; + } - case FILE_ENTRY_DESCRIPTOR: { - cl_error_t temp = findFileEntries(buffer, &fileEntryList); - if (CL_SUCCESS != temp) { - ret = temp; - goto done; - } - break; + case FILE_ENTRY_DESCRIPTOR: { + cl_error_t temp = findFileEntries((const uint8_t *)file_volume_tag, &fileEntryList); + if (CL_SUCCESS != temp) { + ret = temp; + goto done; } + break; + } - case TERMINATING_DESCRIPTOR: - break; + case EXTENDED_FILE_ENTRY_DESCRIPTOR: { + // Not supported yet. Skip. + break; + } - default: { - /* Dump all the files here. */ - size_t i; - size_t cnt = fileIdentifierList.cnt; + case TERMINATING_DESCRIPTOR: { + // Skip. + break; + } - /* The number of file entries should match the number of file identifiers, but in the - * case that the file is malformed, we are going to do the best we can to extract as much as we can. - */ - if (fileEntryList.cnt < cnt) { - cnt = fileEntryList.cnt; - } + case INVALID_DESCRIPTOR: { + // Skip. + break; + } - for (i = 0; i < cnt; i++) { - if (!parseFileEntryDescriptor(ctx, - (const uint8_t *const)fileEntryList.idxs[i], - pd, lvd, (FileIdentifierDescriptor *)fileIdentifierList.idxs[i])) { - goto done; - } - } + default: { + // TODO: Something feels wrong about doing this in `default:`. + // Is there a specific value we can look for to be certain we found them all? + // Right now this code appears to work by running into an invalid tagId when + // actually is out of descriptors and starts indexing into file data. + // Ideally we would end the loop when we know we've found all the descriptors, + // and then do this after the loop. - /* Start looking for the next volume */ - isInitialized = false; - break; + cli_dbgmsg("cli_scanudf: Parsing %d file entries.\n", fileEntryList.cnt); + + /* Dump all the files here. */ + size_t cnt = fileIdentifierList.cnt; + + /* The number of file entries should match the number of file identifiers, but in the + * case that the file is malformed, we are going to do the best we can to extract as much as we can. + */ + if (fileEntryList.cnt < cnt) { + cnt = fileEntryList.cnt; + } + + for (i = 0; i < cnt; i++) { + if (!parseFileEntryDescriptor(ctx, + (FileEntryDescriptor *)fileEntryList.idxs[i], + pd, lvd, (FileIdentifierDescriptor *)fileIdentifierList.idxs[i])) { + cli_dbgmsg("cli_scanudf: Failed to extract file %zu\n", i); + goto done; + } } + + /* + * We're done with this volume. Release our pointers and free up our pointer lists. + * Start looking for the next volume. + */ + fmap_unneed_ptr(ctx->fmap, iuvd, VOLUME_DESCRIPTOR_SIZE); + iuvd = NULL; + fmap_unneed_ptr(ctx->fmap, lvd, VOLUME_DESCRIPTOR_SIZE); + lvd = NULL; + fmap_unneed_ptr(ctx->fmap, file_volume_tag, VOLUME_DESCRIPTOR_SIZE); + file_volume_tag = NULL; + + isInitialized = false; + break; } } @@ -880,8 +985,14 @@ cl_error_t cli_scanudf(cli_ctx *ctx, const size_t offset) freePointerList(&fileIdentifierList); freePointerList(&fileEntryList); - for (idx = offset; idx <= lastOffset; idx += VOLUME_DESCRIPTOR_SIZE) { - fmap_unneed_off(ctx->fmap, idx, VOLUME_DESCRIPTOR_SIZE); + if (NULL != iuvd) { + fmap_unneed_ptr(ctx->fmap, iuvd, VOLUME_DESCRIPTOR_SIZE); + } + if (NULL != lvd) { + fmap_unneed_ptr(ctx->fmap, lvd, VOLUME_DESCRIPTOR_SIZE); + } + if (NULL != file_volume_tag) { + fmap_unneed_ptr(ctx->fmap, file_volume_tag, VOLUME_DESCRIPTOR_SIZE); } return ret; diff --git a/libclamav/udf.h b/libclamav/udf.h index 471dae0c2a..c40027635a 100644 --- a/libclamav/udf.h +++ b/libclamav/udf.h @@ -25,6 +25,7 @@ #define UDF_EMPTY_LEN 32768 +// All Volume Descriptors are the same size. #define VOLUME_DESCRIPTOR_SIZE 0x800 #ifndef HAVE_ATTRIB_PACKED @@ -65,6 +66,8 @@ typedef struct __attribute__((packed)) { } lb_addr; + +// Long allocation descriptor typedef struct __attribute__((packed)) { uint32_t length; // 4/14.14.1.1 /*30 least significant bits are length in bytes. @@ -183,6 +186,7 @@ typedef struct __attribute__((packed)) { long_ad icb; + /*L_IU specified in 1/7.1.3 */ uint16_t implementationLength; uint8_t rest[1]; @@ -195,7 +199,7 @@ typedef struct __attribute__((packed)) { static uint32_t getFileIdentifierDescriptorPaddingLength(const FileIdentifierDescriptor* const fid) { uint32_t ret = 0; - uint32_t tmp = fid->implementationLength + fid->fileIdentifierLength + 38; + uint32_t tmp = le16_to_host(fid->implementationLength) + fid->fileIdentifierLength + 38; ret = tmp + 3; ret = ret / 4; @@ -207,8 +211,10 @@ static uint32_t getFileIdentifierDescriptorPaddingLength(const FileIdentifierDes static inline size_t getFileIdentifierDescriptorSize(const FileIdentifierDescriptor* fid) { - - return FILE_IDENTIFIER_DESCRIPTOR_SIZE_KNOWN + fid->implementationLength + fid->fileIdentifierLength + getFileIdentifierDescriptorPaddingLength(fid); + return FILE_IDENTIFIER_DESCRIPTOR_SIZE_KNOWN + + le16_to_host(fid->implementationLength) + + fid->fileIdentifierLength + + getFileIdentifierDescriptorPaddingLength(fid); } typedef struct __attribute__((packed)) { @@ -260,7 +266,7 @@ typedef struct __attribute__((packed)) { #define FILE_ENTRY_DESCRIPTOR_SIZE_KNOWN (sizeof(FileEntryDescriptor) - 1) static inline size_t getFileEntryDescriptorSize(const FileEntryDescriptor* fed) { - return FILE_ENTRY_DESCRIPTOR_SIZE_KNOWN + fed->extendedAttrLen + fed->allocationDescLen; + return FILE_ENTRY_DESCRIPTOR_SIZE_KNOWN + le32_to_host(fed->extendedAttrLen) + le32_to_host(fed->allocationDescLen); } typedef struct __attribute__((packed)) { @@ -317,6 +323,7 @@ typedef struct __attribute__((packed)) { } ExtendedFileEntryDescriptor; +// Short allocation descriptor typedef struct __attribute__((packed)) { uint32_t length; @@ -514,6 +521,13 @@ typedef struct __attribute__((packed)) { } FileSetDescriptor; +typedef struct __attribute__((packed)) { + uint8_t structType; + char standardIdentifier[5]; + uint8_t structVersion; + uint8_t rest[2041]; +} GenericVolumeStructureDescriptor; + #ifdef HAVE_PRAGMA_PACK #pragma pack() #endif diff --git a/libclamunrar_iface/unrar_iface.h b/libclamunrar_iface/unrar_iface.h index 9cbed12eea..834d44c75b 100644 --- a/libclamunrar_iface/unrar_iface.h +++ b/libclamunrar_iface/unrar_iface.h @@ -57,7 +57,7 @@ typedef enum cl_unrar_error_tag { typedef struct unrar_metadata_tag { uint64_t pack_size; uint64_t unpack_size; - char filename[1024]; + char filename[1024 + 1]; uint32_t crc; unsigned int encrypted; uint8_t method; diff --git a/libfreshclam/libfreshclam_internal.c b/libfreshclam/libfreshclam_internal.c index 94e5d5cd00..a0cd86dfde 100644 --- a/libfreshclam/libfreshclam_internal.c +++ b/libfreshclam/libfreshclam_internal.c @@ -824,7 +824,7 @@ size_t HeaderCallback(char *buffer, size_t totBytes = size * nitems; if (totBytes >= strlen(needle) + CFRAY_LEN) { if (0 == strncmp(needle, buffer, strlen(needle))) { - uint8_t **last = (uint8_t **)userdata; + uint8_t *last = (uint8_t *)userdata; memcpy(last, &(buffer[strlen(needle)]), CFRAY_LEN); last[CFRAY_LEN] = 0; } @@ -1315,7 +1315,7 @@ static fc_error_t downloadFile( logg(LOGG_ERROR, "downloadFile: Failed to set write-data file handle for curl session.\n"); } - if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_HEADERDATA, &g_lastRay)) { + if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_HEADERDATA, g_lastRay)) { logg(LOGG_ERROR, "downloadFile: Failed to set header-data for header callback for curl session.\n"); }