From 55491147fce2bc03ffb602a3985e7fd4e32169a3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 17 May 2013 10:17:28 -0500 Subject: [PATCH 1/1] dentry.c, security.c: Cleanups, fixes --- src/dentry.c | 78 +++++++++++++++++++---------------------- src/metadata_resource.c | 65 +++++++++++++++------------------- src/security.c | 15 ++++---- src/verify.c | 19 +++++----- 4 files changed, 79 insertions(+), 98 deletions(-) diff --git a/src/dentry.c b/src/dentry.c index 9411f85d..5082eac6 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -1368,11 +1368,11 @@ replace_forbidden_characters(utf16lechar *name) * @p: Pointer to buffer that starts with the first alternate stream entry. * * @inode: Inode to load the alternate data streams into. - * @inode->i_num_ads must have been set to the number of - * alternate data streams that are expected. + * @inode->i_num_ads must have been set to the number of + * alternate data streams that are expected. * * @remaining_size: Number of bytes of data remaining in the buffer pointed - * to by @p. + * to by @p. * * * Return 0 on success or nonzero on failure. On success, inode->i_ads_entries @@ -1387,11 +1387,14 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, struct wim_ads_entry *ads_entries; int ret; + /* Allocate an array for our in-memory representation of the alternate + * data stream entries. */ num_ads = inode->i_num_ads; ads_entries = CALLOC(num_ads, sizeof(inode->i_ads_entries[0])); if (!ads_entries) goto out_of_memory; + /* Read the entries into our newly allocated buffer. */ for (u16 i = 0; i < num_ads; i++) { u64 length; struct wim_ads_entry *cur_entry; @@ -1410,7 +1413,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, length = le64_to_cpu(disk_entry->length); /* Make sure the length field is neither so small it doesn't - * include all the fixed-length data, or so large it overflows + * include all the fixed-length data nor so large it overflows * the metadata resource buffer. */ if (length < sizeof(struct wim_ads_entry_on_disk) || length > nbytes_remaining) @@ -1419,9 +1422,8 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, /* Read the rest of the fixed-length data. */ cur_entry->reserved = le64_to_cpu(disk_entry->reserved); - copy_hash(cur_entry->hash, disk_entry->hash); - cur_entry->stream_name_nbytes = le16_to_cpu(cur_entry->stream_name_nbytes); + cur_entry->stream_name_nbytes = le16_to_cpu(disk_entry->stream_name_nbytes); /* If stream_name_nbytes != 0, this is a named stream. * Otherwise this is an unnamed stream, or in some cases (bugs @@ -1430,8 +1432,6 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, * the fact that the real unnamed stream entry has a nonzero * hash field. */ if (cur_entry->stream_name_nbytes) { - u64 length_no_padding; - /* The name is encoded in UTF16-LE, which uses 2-byte * coding units, so the length of the name had better be * an even number of bytes... */ @@ -1452,7 +1452,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, memcpy(cur_entry->stream_name, disk_entry->stream_name, cur_entry->stream_name_nbytes); - cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = 0; + cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = cpu_to_le16(0); replace_forbidden_characters(cur_entry->stream_name); } @@ -1472,9 +1472,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, nbytes_remaining -= length; } inode->i_ads_entries = ads_entries; -#ifdef WITH_FUSE inode->i_next_stream_id = inode->i_num_ads + 1; -#endif ret = 0; goto out; out_of_memory: @@ -1512,6 +1510,10 @@ out: * buffers. On success, the dentry->length field must be examined. If zero, * this was a special "end of directory" dentry and not a real dentry. If * nonzero, this was a real dentry. + * + * Possible errors include: + * WIMLIB_ERR_NOMEM + * WIMLIB_ERR_INVALID_DENTRY */ int read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len, @@ -1525,44 +1527,41 @@ read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len, u16 file_name_nbytes; int ret; struct wim_inode *inode; - const struct wim_dentry_on_disk *disk_dentry; const u8 *p = &metadata_resource[offset]; + const struct wim_dentry_on_disk *disk_dentry = + (const struct wim_dentry_on_disk*)p; if ((uintptr_t)p & 7) WARNING("WIM dentry is not 8-byte aligned"); dentry_common_init(dentry); - /*Make sure the dentry really fits into the metadata resource.*/ - if (offset + sizeof(u64) < offset || - offset + sizeof(u64) > metadata_resource_len) + /* Before reading the whole dentry, we need to read just the length. + * This is because a dentry of length 8 (that is, just the length field) + * terminates the list of sibling directory entries. */ + if (offset + sizeof(u64) > metadata_resource_len || + offset + sizeof(u64) < offset) { ERROR("Directory entry starting at %"PRIu64" ends past the " "end of the metadata resource (size %"PRIu64")", offset, metadata_resource_len); return WIMLIB_ERR_INVALID_DENTRY; } - - disk_dentry = (const struct wim_dentry_on_disk*)p; - - /* Before reading the whole dentry, we need to read just the length. - * This is because a dentry of length 8 (that is, just the length field) - * terminates the list of sibling directory entries. */ dentry->length = le64_to_cpu(disk_dentry->length); /* A zero length field (really a length of 8, since that's how big the * directory entry is...) indicates that this is the end of directory * dentry. We do not read it into memory as an actual dentry, so just - * return successfully in that case. */ + * return successfully in this case. */ if (dentry->length == 8) dentry->length = 0; if (dentry->length == 0) return 0; /* Now that we have the actual length provided in the on-disk structure, - * make sure it doesn't overflow the metadata buffer. */ - if (offset + dentry->length >= metadata_resource_len - || offset + dentry->length < offset) + * again make sure it doesn't overflow the metadata resource buffer. */ + if (offset + dentry->length > metadata_resource_len || + offset + dentry->length < offset) { ERROR("Directory entry at offset %"PRIu64" and with size " "%"PRIu64" ends past the end of the metadata resource " @@ -1706,7 +1705,6 @@ read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len, goto out_free_short_name; } } -out_success: /* We've read all the data for this dentry. Set the names and their * lengths, and we've done. */ dentry->d_inode = inode; @@ -1761,12 +1759,12 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, return 0; /* Find and read all the children of @dentry. */ - while (1) { + for (;;) { /* Read next child of @dentry into @cur_child. */ ret = read_dentry(metadata_resource, metadata_resource_len, cur_offset, &cur_child); - if (ret != 0) + if (ret) break; /* Check for end of directory. */ @@ -1791,7 +1789,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, if (child->subdir_offset != 0) { ret = read_dentry_tree(metadata_resource, metadata_resource_len, child); - if (ret != 0) + if (ret) break; } @@ -1812,7 +1810,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, * @p: The memory location to write the data to. * * Returns the pointer to the byte after the last byte we wrote as part of the - * dentry, including any alternate data streams entry. + * dentry, including any alternate data stream entries. */ static u8 * write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p) @@ -1836,12 +1834,8 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p) disk_dentry->creation_time = cpu_to_le64(inode->i_creation_time); disk_dentry->last_access_time = cpu_to_le64(inode->i_last_access_time); disk_dentry->last_write_time = cpu_to_le64(inode->i_last_write_time); - - if (inode->i_resolved) - hash = inode->i_lte->hash; - else - hash = inode->i_hash; - copy_hash(disk_dentry->unnamed_stream_hash, inode_stream_hash(inode, 0)); + hash = inode_stream_hash(inode, 0); + copy_hash(disk_dentry->unnamed_stream_hash, hash); if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { disk_dentry->reparse.rp_unknown_1 = cpu_to_le32(inode->i_rp_unknown_1); disk_dentry->reparse.reparse_tag = cpu_to_le32(inode->i_reparse_tag); @@ -1870,19 +1864,19 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p) /* We calculate the correct length of the dentry ourselves because the * dentry->length field may been set to an unexpected value from when we * read the dentry in (for example, there may have been unknown data - * appended to the end of the dentry...) */ + * appended to the end of the dentry...). Furthermore, the dentry may + * have been renamed, thus changing its needed length. */ disk_dentry->length = cpu_to_le64(p - orig_p); - /* Write the alternate data streams entries, if there are any. */ - for (u16 i = 0; i < inode->i_num_ads; i++) - { + /* Write the alternate data streams entries, if any. */ + for (u16 i = 0; i < inode->i_num_ads; i++) { const struct wim_ads_entry *ads_entry = - &inode->i_ads_entries[i]; + &inode->i_ads_entries[i]; struct wim_ads_entry_on_disk *disk_ads_entry = (struct wim_ads_entry_on_disk*)p; + orig_p = p; disk_ads_entry->reserved = cpu_to_le64(ads_entry->reserved); - orig_p = p; hash = inode_stream_hash(inode, i + 1); copy_hash(disk_ads_entry->hash, hash); diff --git a/src/metadata_resource.c b/src/metadata_resource.c index da0be288..5b22ab6d 100644 --- a/src/metadata_resource.c +++ b/src/metadata_resource.c @@ -52,14 +52,14 @@ * Returns: Zero on success, nonzero on failure. */ int -read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd) +read_metadata_resource(WIMStruct *wim, struct wim_image_metadata *imd) { u8 *buf; - u32 dentry_offset; int ret; - struct wim_dentry *dentry; + struct wim_dentry *root; const struct wim_lookup_table_entry *metadata_lte; u64 metadata_len; + struct wim_security_data *security_data; metadata_lte = imd->metadata_lte; metadata_len = wim_resource_size(metadata_lte); @@ -73,7 +73,7 @@ read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd) /* There is no way the metadata resource could possibly be less than (8 * + WIM_DENTRY_DISK_SIZE) bytes, where the 8 is for security data (with * no security descriptors) and WIM_DENTRY_DISK_SIZE is for the root - * dentry. */ + * entry. */ if (metadata_len < 8 + WIM_DENTRY_DISK_SIZE) { ERROR("Expected at least %u bytes for the metadata resource", 8 + WIM_DENTRY_DISK_SIZE); @@ -110,79 +110,70 @@ read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd) * the offset of the root dentry. * * Here we read the security data into a wim_security_data structure, - * and if successful, go ahead and calculate the offset in the metadata - * resource of the root dentry. */ + * which takes case of rouding total_length. If successful, go ahead + * and calculate the offset in the metadata resource of the root dentry. + * */ - wimlib_assert(imd->security_data == NULL); - ret = read_wim_security_data(buf, metadata_len, &imd->security_data); + ret = read_wim_security_data(buf, metadata_len, &security_data); if (ret) goto out_free_buf; - dentry_offset = (imd->security_data->total_length + 7) & ~7; - - if (dentry_offset == 0) { - ERROR("Integer overflow while reading metadata resource"); - ret = WIMLIB_ERR_INVALID_SECURITY_DATA; - goto out_free_security_data; - } - DEBUG("Reading root dentry"); /* Allocate memory for the root dentry and read it into memory */ - dentry = MALLOC(sizeof(struct wim_dentry)); - if (!dentry) { - ERROR("Failed to allocate %zu bytes for root dentry", - sizeof(struct wim_dentry)); + root = MALLOC(sizeof(struct wim_dentry)); + if (!root) { ret = WIMLIB_ERR_NOMEM; goto out_free_security_data; } - ret = read_dentry(buf, metadata_len, dentry_offset, dentry); - - /* This is the root dentry, so set its parent to itself. */ - dentry->parent = dentry; + ret = read_dentry(buf, metadata_len, + security_data->total_length, root); - if (ret == 0 && dentry->length == 0) { + if (ret == 0 && root->length == 0) { ERROR("Metadata resource cannot begin with end-of-directory entry!"); ret = WIMLIB_ERR_INVALID_DENTRY; } - if (ret != 0) { - FREE(dentry); + if (ret) { + FREE(root); goto out_free_security_data; } - inode_add_dentry(dentry, dentry->d_inode); + /* This is the root dentry, so set its parent to itself. */ + root->parent = root; + + inode_add_dentry(root, root->d_inode); /* Now read the entire directory entry tree into memory. */ DEBUG("Reading dentry tree"); - ret = read_dentry_tree(buf, metadata_len, dentry); + ret = read_dentry_tree(buf, metadata_len, root); if (ret) goto out_free_dentry_tree; /* Build hash table that maps hard link group IDs to dentry sets */ - ret = dentry_tree_fix_inodes(dentry, &imd->inode_list); + ret = dentry_tree_fix_inodes(root, &imd->inode_list); if (ret) goto out_free_dentry_tree; - if (!w->all_images_verified) { + if (!wim->all_images_verified) { DEBUG("Running miscellaneous verifications on the dentry tree"); - for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL); - ret = for_dentry_in_tree(dentry, verify_dentry, w); + for_lookup_table_entry(wim->lookup_table, lte_zero_real_refcnt, NULL); + ret = for_dentry_in_tree(root, verify_dentry, wim); if (ret) goto out_free_dentry_tree; } DEBUG("Done reading image metadata"); - imd->root_dentry = dentry; + imd->root_dentry = root; + imd->security_data = security_data; INIT_LIST_HEAD(&imd->unhashed_streams); goto out_free_buf; out_free_dentry_tree: - free_dentry_tree(dentry, NULL); + free_dentry_tree(root, wim->lookup_table); out_free_security_data: - free_wim_security_data(imd->security_data); - imd->security_data = NULL; + free_wim_security_data(security_data); out_free_buf: FREE(buf); return ret; diff --git a/src/security.c b/src/security.c index dc3c4096..4cd898b5 100644 --- a/src/security.c +++ b/src/security.c @@ -287,7 +287,6 @@ out_align_total_length: "%u bytes, but calculated %u bytes", sd->total_length, (unsigned)total_len); } -out_return_sd: *sd_ret = sd; ret = 0; goto out; @@ -316,23 +315,23 @@ write_wim_security_data(const struct wim_security_data * restrict sd, u8 *orig_p = p; struct wim_security_data_disk *sd_disk = (struct wim_security_data_disk*)p; + u32 num_entries = sd->num_entries; sd_disk->total_length = cpu_to_le32(sd->total_length); - sd_disk->num_entries = cpu_to_le32(sd->num_entries); + sd_disk->num_entries = cpu_to_le32(num_entries); - for (u32 i = 0; i < sd->num_entries; i++) + for (u32 i = 0; i < num_entries; i++) sd_disk->sizes[i] = cpu_to_le64(sd->sizes[i]); - p = (u8*)&sd_disk->sizes[sd_disk->num_entries]; + p = (u8*)&sd_disk->sizes[num_entries]; - for (u32 i = 0; i < sd->num_entries; i++) + for (u32 i = 0; i < num_entries; i++) p = mempcpy(p, sd->descriptors[i], sd->sizes[i]); - while (p - orig_p < sd->total_length) + while ((uintptr_t)p & 7) *p++ = 0; wimlib_assert(p - orig_p == sd->total_length); - wimlib_assert(((uintptr_t)p & 7) == 0); DEBUG("Successfully wrote security data."); return p; @@ -554,7 +553,7 @@ sd_set_add_sd(struct wim_sd_set *sd_set, const char *descriptor, size_t size) struct sd_node *new; u8 **descriptors; u64 *sizes; - char *descr_copy; + u8 *descr_copy; struct wim_security_data *sd; bool bret; diff --git a/src/verify.c b/src/verify.c index 89da4b8d..56e77ef7 100644 --- a/src/verify.c +++ b/src/verify.c @@ -41,7 +41,6 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) const struct wim_security_data *sd = wim_const_security_data(w); struct wim_dentry *first_dentry = inode_first_dentry(inode); struct wim_dentry *dentry; - int ret = WIMLIB_ERR_INVALID_DENTRY; /* Check the security ID. -1 is valid and means "no security * descriptor". Anything else has to be a valid index into the WIM @@ -49,7 +48,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) if (inode->i_security_id < -1) { ERROR("Dentry `%"TS"' has an invalid security ID (%d)", dentry_full_path(first_dentry), inode->i_security_id); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } if (inode->i_security_id >= 0 && @@ -59,7 +58,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) "(there are only %u entries in the security table)", dentry_full_path(first_dentry), inode->i_security_id, sd->num_entries); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } /* Check that lookup table entries for all the inode's stream exist, @@ -77,7 +76,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) ERROR("Could not find lookup table entry for stream " "%u of dentry `%"TS"'", i, dentry_full_path(first_dentry)); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } if (lte) lte->real_refcnt += inode->i_nlink; @@ -95,7 +94,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) if (num_unnamed_streams > 1) { ERROR("Dentry `%"TS"' has multiple (%u) un-named streams", dentry_full_path(first_dentry), num_unnamed_streams); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } /* Files cannot have multiple DOS names, even if they have multiple @@ -109,7 +108,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) "both `%"TS"' and `%"TS"'", dentry_full_path(dentry_with_dos_name), dentry_full_path(dentry)); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } dentry_with_dos_name = dentry; } @@ -119,13 +118,11 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w) if (inode->i_nlink > 1 && inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) { ERROR("Hard-linked directory `%"TS"' is unsupported", dentry_full_path(first_dentry)); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } inode->i_verified = 1; - ret = 0; -out: - return ret; + return 0; } /* Run some miscellaneous verifications on a WIM dentry */ @@ -140,7 +137,7 @@ verify_dentry(struct wim_dentry *dentry, void *wim) * in which case we need to force the inode to be verified again.) */ if (!dentry->d_inode->i_verified) { ret = verify_inode(dentry->d_inode, w); - if (ret != 0) + if (ret) return ret; } -- 2.43.0