X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fresource.c;h=c6da07a29ed6b709dbf493acc03ed3ec0a499435;hb=87a0d455554a9e06bc47457981e370c06b9bcbac;hp=ffcd7530a35f5ab590ad4ac9cc226701d7c389a1;hpb=d0e7f039e4ab206b9fd973c983e3fb841fcd2bf2;p=wimlib diff --git a/src/resource.c b/src/resource.c index ffcd7530..c6da07a2 100644 --- a/src/resource.c +++ b/src/resource.c @@ -435,6 +435,10 @@ u8 *put_resource_entry(u8 *p, const struct resource_entry *entry) int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], size_t size, u64 offset, bool raw) { + int ctype; + int ret = 0; + FILE *fp; + /* We shouldn't be allowing read over-runs in any part of the library. * */ if (raw) @@ -442,16 +446,13 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], else wimlib_assert(offset + size <= lte->resource_entry.original_size); - int ctype; - int ret; - FILE *fp; switch (lte->resource_location) { case RESOURCE_IN_WIM: /* The resource is in a WIM file, and its WIMStruct is given by * the lte->wim member. The resource may be either compressed * or uncompressed. */ - wimlib_assert(lte->wim); - wimlib_assert(lte->wim->fp); + wimlib_assert(lte->wim != NULL); + wimlib_assert(lte->wim->fp != NULL); ctype = wim_resource_compression_type(lte); wimlib_assert(ctype != WIM_COMPRESSION_TYPE_NONE || @@ -459,15 +460,15 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], lte->resource_entry.size)); if (raw || ctype == WIM_COMPRESSION_TYPE_NONE) - return read_uncompressed_resource(lte->wim->fp, - lte->resource_entry.offset + offset, - size, buf); + ret = read_uncompressed_resource(lte->wim->fp, + lte->resource_entry.offset + offset, + size, buf); else - return read_compressed_resource(lte->wim->fp, - lte->resource_entry.size, - lte->resource_entry.original_size, - lte->resource_entry.offset, - ctype, size, offset, buf); + ret = read_compressed_resource(lte->wim->fp, + lte->resource_entry.size, + lte->resource_entry.original_size, + lte->resource_entry.offset, + ctype, size, offset, buf); break; case RESOURCE_IN_STAGING_FILE: case RESOURCE_IN_FILE_ON_DISK: @@ -484,46 +485,42 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], if (!fp) { ERROR_WITH_ERRNO("Failed to open the file " "`%s'", lte->file_on_disk); - return WIMLIB_ERR_OPEN; + ret = WIMLIB_ERR_OPEN; + break; } } ret = read_uncompressed_resource(fp, offset, size, buf); if (fp != lte->file_on_disk_fp) fclose(fp); - return ret; break; case RESOURCE_IN_ATTACHED_BUFFER: /* The resource is directly attached uncompressed in an * in-memory buffer. */ - wimlib_assert(lte->attached_buffer); + wimlib_assert(lte->attached_buffer != NULL); memcpy(buf, lte->attached_buffer + offset, size); - return 0; break; #ifdef WITH_NTFS_3G case RESOURCE_IN_NTFS_VOLUME: - wimlib_assert(lte->ntfs_loc); - if (lte->attr) { - u64 adjusted_offset; + wimlib_assert(lte->ntfs_loc != NULL); + wimlib_assert(lte->attr != NULL); + { if (lte->ntfs_loc->is_reparse_point) - adjusted_offset = offset + 8; - else - adjusted_offset = offset; - if (ntfs_attr_pread(lte->attr, offset, size, buf) == size) { - return 0; - } else { + offset += 8; + if (ntfs_attr_pread(lte->attr, offset, size, buf) != size) { ERROR_WITH_ERRNO("Error reading NTFS attribute " "at `%s'", lte->ntfs_loc->path_utf8); - return WIMLIB_ERR_NTFS_3G; + ret = WIMLIB_ERR_NTFS_3G; } - } else { - wimlib_assert(0); + break; } - break; #endif default: - assert(0); + wimlib_assert(0); + ret = -1; + break; } + return ret; } /* @@ -571,7 +568,6 @@ begin_wim_resource_chunk_tab(const struct lookup_table_entry *lte, struct chunk_table *chunk_tab = CALLOC(1, alloc_size); int ret; - if (!chunk_tab) { ERROR("Failed to allocate chunk table for %"PRIu64" byte " "resource", size); @@ -757,8 +753,8 @@ static int write_wim_resource(struct lookup_table_entry *lte, u64 original_size; u64 old_compressed_size; u64 new_compressed_size; - u64 offset = 0; - int ret = 0; + u64 offset; + int ret; struct chunk_table *chunk_tab = NULL; bool raw; off_t file_offset; @@ -859,6 +855,7 @@ static int write_wim_resource(struct lookup_table_entry *lte, /* While there are still bytes remaining in the WIM resource, read a * chunk of the resource, update SHA1, then write that chunk using the * desired compression type. */ + offset = 0; do { u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE); ret = read_wim_resource(lte, buf, to_read, offset, raw); @@ -941,22 +938,23 @@ static int write_wim_resource(struct lookup_table_entry *lte, if (ftruncate(fileno(out_fp), file_offset + out_res_entry->size) != 0) { ERROR_WITH_ERRNO("Failed to truncate output WIM file"); ret = WIMLIB_ERR_WRITE; + goto out_fclose; + } + } else { + if (out_res_entry) { + out_res_entry->size = new_compressed_size; + out_res_entry->original_size = original_size; + out_res_entry->offset = file_offset; + out_res_entry->flags = lte->resource_entry.flags + & ~WIM_RESHDR_FLAG_COMPRESSED; + if (out_ctype != WIM_COMPRESSION_TYPE_NONE) + out_res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED; } - goto out_fclose; - } - wimlib_assert(new_compressed_size <= original_size || raw); - if (out_res_entry) { - out_res_entry->size = new_compressed_size; - out_res_entry->original_size = original_size; - out_res_entry->offset = file_offset; - out_res_entry->flags = lte->resource_entry.flags - & ~WIM_RESHDR_FLAG_COMPRESSED; - if (out_ctype != WIM_COMPRESSION_TYPE_NONE) - out_res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED; } + ret = 0; out_fclose: if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK - && lte->file_on_disk_fp) { + && lte->file_on_disk_fp) { fclose(lte->file_on_disk_fp); lte->file_on_disk_fp = NULL; } @@ -965,9 +963,9 @@ out_fclose: if (lte->attr) { ntfs_attr_close(lte->attr); lte->attr = NULL; - } if (ni) { - ntfs_inode_close(ni); } + if (ni) + ntfs_inode_close(ni); } #endif out: @@ -983,7 +981,7 @@ static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size, struct resource_entry *out_res_entry, u8 hash[SHA1_HASH_SIZE]) { - /* Set up a temporary lookup table entry that we provide to + /* Set up a temporary lookup table entry to provide to * write_wim_resource(). */ struct lookup_table_entry lte; int ret; @@ -1164,6 +1162,12 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd) return WIMLIB_ERR_INVALID_RESOURCE_SIZE; } + if (sizeof(size_t) < 8 && metadata_len > 0xffffffff) { + ERROR("Metadata resource is too large (%"PRIu64" bytes", + metadata_len); + return WIMLIB_ERR_INVALID_RESOURCE_SIZE; + } + /* Allocate memory for the uncompressed metadata resource. */ buf = MALLOC(metadata_len); @@ -1191,14 +1195,18 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd) * and if successful, go ahead and calculate the offset in the metadata * resource of the root dentry. */ + wimlib_assert(imd->security_data == NULL); ret = read_security_data(buf, metadata_len, &imd->security_data); if (ret != 0) goto out_free_buf; - get_u32(buf, &dentry_offset); - if (dentry_offset == 0) - dentry_offset = 8; - dentry_offset = (dentry_offset + 7) & ~7; + 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; + } /* Allocate memory for the root dentry and read it into memory */ dentry = MALLOC(sizeof(struct dentry)); @@ -1277,7 +1285,6 @@ int write_metadata_resource(WIMStruct *w) struct lookup_table_entry *lte; u64 metadata_original_size; const struct wim_security_data *sd; - const unsigned random_tail_len = 20; DEBUG("Writing metadata resource for image %d", w->current_image); @@ -1286,7 +1293,8 @@ int write_metadata_resource(WIMStruct *w) /* We do not allow the security data pointer to be NULL, although it may * point to an empty security data with no entries. */ - wimlib_assert(sd); + wimlib_assert(root != NULL); + wimlib_assert(sd != NULL); /* Offset of first child of the root dentry. It's equal to: * - The total length of the security data, rounded to the next 8-byte @@ -1302,7 +1310,7 @@ int write_metadata_resource(WIMStruct *w) calculate_subdir_offsets(root, &subdir_offset); /* Total length of the metadata resource (uncompressed) */ - metadata_original_size = subdir_offset + random_tail_len; + metadata_original_size = subdir_offset; /* Allocate a buffer to contain the uncompressed metadata resource */ buf = MALLOC(metadata_original_size); @@ -1316,26 +1324,18 @@ int write_metadata_resource(WIMStruct *w) p = write_security_data(sd, buf); /* Write the dentry tree into the resource buffer */ - DEBUG("Writing dentry tree."); p = write_dentry_tree(root, p); - /* - * Append 20 random bytes to the metadata resource so that we don't have - * identical metadata resources if we happen to append exactly the same - * image twice without any changes in timestamps. If this were to - * happen, it would cause confusion about the number and order of images - * in the WIM. - */ - randomize_byte_array(p, random_tail_len); - /* We MUST have exactly filled the buffer; otherwise we calculated its * size incorrectly or wrote the data incorrectly. */ - wimlib_assert(p - buf + random_tail_len == metadata_original_size); + wimlib_assert(p - buf == metadata_original_size); /* Get the lookup table entry for the metadata resource so we can update * it. */ lte = wim_metadata_lookup_table_entry(w); + wimlib_assert(lte != NULL); + /* Write the metadata resource to the output WIM using the proper * compression type. The lookup table entry for the metadata resource * is updated. */ @@ -1349,14 +1349,17 @@ int write_metadata_resource(WIMStruct *w) /* It's very likely the SHA1 message digest of the metadata resource * changed, so re-insert the lookup table entry into the lookup table. + * + * We do not check for other lookup table entries having the same SHA1 + * message digest. It's possible for 2 absolutely identical images to + * be added, therefore causing 2 identical metadata resources to be in + * the WIM. However, in this case, it's expected for 2 separate lookup + * table entries to be created, even though this doesn't make a whole + * lot of sense since they will share the same SHA1 message digest. * */ lookup_table_unlink(w->lookup_table, lte); lookup_table_insert(w->lookup_table, lte); - /* We do not allow a metadata resource to be referenced multiple times, - * and the 20 random bytes appended to it should make it extremely - * likely for each metadata resource to be unique, even if the exact - * same image is captured. */ wimlib_assert(lte->out_refcnt == 0); lte->out_refcnt = 1;