diff --git a/README.md b/README.md index fcd1f09..bf5e8a6 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,10 @@ Any and all contributions are welcome. Included is also a `cadius.pro` file you ## Changelog +#### 1.4.5 +- Fix `os_GetFolderFiles` calloc too small. +- AppleSingle check for OOB accesses (thanks [@peterferrie](https://github.com/peterferrie)). [#34](https://github.com/mach-kernel/cadius/pull/34) + #### 1.4.4 - Fix 140KiB volume size assertion (thanks [@inexorabletash](https://github.com/inexorabletash)): [#30](https://github.com/mach-kernel/cadius/pull/27) diff --git a/Src/File_AppleSingle.c b/Src/File_AppleSingle.c index 3973e6a..5362bf6 100644 --- a/Src/File_AppleSingle.c +++ b/Src/File_AppleSingle.c @@ -20,8 +20,9 @@ static uint16_t as_field16(uint16_t num) * @param buf * @return */ -bool ASIsAppleSingle(unsigned char *buf) +bool ASIsAppleSingle(unsigned char *buf, size_t buflen) { + if (buflen < sizeof(AS_MAGIC)) return false; int buf_magic; memcpy(&buf_magic, buf, sizeof(AS_MAGIC)); buf_magic = as_field32(buf_magic); @@ -35,9 +36,11 @@ bool ASIsAppleSingle(unsigned char *buf) * @param buf The buffer * @return */ -struct as_file_header *ASParseHeader(unsigned char *buf) +struct as_file_header *ASParseHeader(unsigned char *buf, size_t buflen) { + if (buflen < sizeof(as_file_header)) return NULL; struct as_file_header *header = malloc(sizeof(as_file_header)); + if (!header) return NULL; struct as_file_header *buf_header = (as_file_header *) buf; header->magic = as_field32(buf_header->magic); @@ -52,9 +55,11 @@ struct as_file_header *ASParseHeader(unsigned char *buf) * @param entry_buf The entry buffer * @return */ -struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf) +struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf, size_t buflen) { + if (buflen < sizeof(as_prodos_info)) return NULL; struct as_prodos_info *prodos_entry = malloc(sizeof(as_prodos_info)); + if (!prodos_entry) return NULL; struct as_prodos_info *buf_prodos_entry = (as_prodos_info *) entry_buf; prodos_entry->access = as_field16(buf_prodos_entry->access); @@ -70,7 +75,7 @@ struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf) * @param buf * @return */ -struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char *buf) +struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char *buf, size_t buflen) { if (!header) { @@ -78,11 +83,12 @@ struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char return NULL; } - struct as_file_entry *entries = malloc( - header->num_entries * sizeof(as_file_entry) - ); + size_t entries_length = header->num_entries * sizeof(as_file_entry); + if (buflen < sizeof(as_file_header) + entries_length) return NULL; + struct as_file_entry *entries = malloc(entries_length); struct as_file_entry *buf_entries = (as_file_entry *) (buf + sizeof(as_file_header)); + memcpy(entries, buf_entries, header->num_entries * sizeof(as_file_entry)); if (IS_LITTLE_ENDIAN) @@ -103,9 +109,10 @@ struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char * @param data The data * @param data_fork_entry The data fork entry */ -void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, as_file_entry *data_fork_entry) +void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, size_t datalen, as_file_entry *data_fork_entry) { if (data_fork_entry->entry_id != data_fork) return; + if (datalen < data_fork_entry->offset + data_fork_entry->length) return; unsigned char *data_entry = malloc(data_fork_entry->length); memcpy(data_entry, data + data_fork_entry->offset, data_fork_entry->length); @@ -123,12 +130,14 @@ void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, a * @param data The data * @param prodos_entry The prodos entry */ -void ASDecorateProdosFileInfo(struct prodos_file *current_file, unsigned char *data, as_file_entry *prodos_entry) +void ASDecorateProdosFileInfo(struct prodos_file *current_file, unsigned char *data, size_t datalen, as_file_entry *prodos_entry) { if (prodos_entry->entry_id != prodos_file_info) return; + if (datalen < prodos_entry->offset + prodos_entry->length) return; struct as_prodos_info *info_meta = ASParseProdosEntry( - data + prodos_entry->offset + data + prodos_entry->offset, + prodos_entry->length ); if (!info_meta) return; @@ -147,19 +156,19 @@ void ASDecorateProdosFileInfo(struct prodos_file *current_file, unsigned char *d * @param current_file * @param data */ -void ASDecorateProdosFile(struct prodos_file *current_file, unsigned char *data) +void ASDecorateProdosFile(struct prodos_file *current_file, unsigned char *data, size_t datalen) { - struct as_file_header *header = ASParseHeader(data); - struct as_file_entry *entries = ASGetEntries(header, data); + struct as_file_header *header = ASParseHeader(data, datalen); + struct as_file_entry *entries = ASGetEntries(header, data, datalen); for (int i = 0; i < header->num_entries; ++i) switch(entries[i].entry_id) { case data_fork: - ASDecorateDataFork(current_file, data, &entries[i]); + ASDecorateDataFork(current_file, data, datalen, &entries[i]); break; case prodos_file_info: - ASDecorateProdosFileInfo(current_file, data, &entries[i]); + ASDecorateProdosFileInfo(current_file, data, datalen, &entries[i]); break; default: logf_info(" Entry ID %d unsupported, ignoring!\n", entries[i].entry_id); diff --git a/Src/File_AppleSingle.h b/Src/File_AppleSingle.h index 75edff1..5fc9e10 100644 --- a/Src/File_AppleSingle.h +++ b/Src/File_AppleSingle.h @@ -70,14 +70,14 @@ typedef struct as_from_prodos #pragma pack(pop) -bool ASIsAppleSingle(unsigned char *buf); +bool ASIsAppleSingle(unsigned char *buf, size_t buflen); -struct as_file_header *ASParseHeader(unsigned char *buf); -struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf); -struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char *buf); +struct as_file_header *ASParseHeader(unsigned char *buf, size_t buflen); +struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf, size_t buflen); +struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char *buf, size_t buflen); -void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, as_file_entry *data_fork_entry); -void ASDeocrateProdosFileInfo(struct prodos_file *current_file, unsigned char *data, as_file_entry *prodos_entry); -void ASDecorateProdosFile(struct prodos_file *current_file, unsigned char *data); +void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, size_t datalen, as_file_entry *data_fork_entry); +void ASDeocrateProdosFileInfo(struct prodos_file *current_file, unsigned char *data, size_t datalen, as_file_entry *prodos_entry); +void ASDecorateProdosFile(struct prodos_file *current_file, unsigned char *data, size_t datalen); struct as_from_prodos ASFromProdosFile(struct prodos_file *file); diff --git a/Src/Main.c b/Src/Main.c index 25fd6e4..e478cf2 100644 --- a/Src/Main.c +++ b/Src/Main.c @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) struct file_descriptive_entry *folder_entry; /* Message Information */ - logf("%s v 1.4.4 (c) Brutal Deluxe 2011-2013.\n",argv[0]); + logf("%s v 1.4.5 (c) Brutal Deluxe 2011-2013.\n",argv[0]); /* Vérification des paramètres */ if(argc < 3) diff --git a/Src/Prodos_Add.c b/Src/Prodos_Add.c index f8c2ca8..97e02bb 100644 --- a/Src/Prodos_Add.c +++ b/Src/Prodos_Add.c @@ -364,12 +364,12 @@ static struct prodos_file *LoadFile(char *file_path_data, bool zero_case_bits) return NULL; } - bool is_apple_single = ASIsAppleSingle(data); + bool is_apple_single = ASIsAppleSingle(data, ¤t_file->data_length); if (is_apple_single) { logf_info(" AppleSingle format detected!\n"); - ASDecorateProdosFile(current_file, data); + ASDecorateProdosFile(current_file, data, ¤t_file->data_length); } else { diff --git a/Src/os/posix.c b/Src/os/posix.c index 009c509..d215284 100644 --- a/Src/os/posix.c +++ b/Src/os/posix.c @@ -77,7 +77,7 @@ int os_GetFolderFiles(char *folder_path, char *hierarchy) if (entry == NULL) break; // +2 for \0 and a possible slash - char *heap_path = calloc(1, strlen(folder_path) + 2); + char *heap_path = calloc(1, strlen(folder_path) + strlen(entry->d_name) + 2); strcpy(heap_path, folder_path); // If there's no trailing dir slash, we append it