Do some more verifications on each dentry after we read them all into memory.
dentry_common_init(dentry);
/*Make sure the dentry really fits into the metadata resource.*/
- if (offset + 8 > metadata_resource_len) {
+ if (offset + 8 > metadata_resource_len || offset + 8 < offset) {
ERROR("Directory entry starting at %"PRIu64" ends past the "
"end of the metadata resource (size %"PRIu64")",
offset, metadata_resource_len);
* not too short, read the rest of it (excluding the alternate data
* streams, but including the file name and short name variable-length
* fields) into memory. */
- if (offset + dentry->length >= metadata_resource_len) {
+ 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 "
"(size %"PRIu64")",
return ret;
}
+/* Run some miscellaneous verifications on a WIM dentry */
+int verify_dentry(struct dentry *dentry, void *wim)
+{
+ const WIMStruct *w = wim;
+ const struct lookup_table *table = w->lookup_table;
+ const struct wim_security_data *sd = wim_const_security_data(w);
+ int ret = WIMLIB_ERR_INVALID_DENTRY;
+
+ /* Check the security ID */
+ if (dentry->security_id < -1) {
+ ERROR("Dentry `%s' has an invalid security ID (%d)",
+ dentry->full_path_utf8, dentry->security_id);
+ goto out;
+ }
+ if (dentry->security_id >= sd->num_entries) {
+ ERROR("Dentry `%s' has an invalid security ID (%d) "
+ "(there are only %u entries in the security table)",
+ dentry->full_path_utf8, dentry->security_id,
+ sd->num_entries);
+ goto out;
+ }
+
+ /* Check that lookup table entries for all the resources exist, except
+ * if the SHA1 message digest is all 0's, which indicates there is
+ * intentionally no resource there. */
+ if (w->hdr.total_parts == 1) {
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ struct lookup_table_entry *lte;
+ const u8 *hash;
+ hash = dentry_stream_hash_unresolved(dentry, i);
+ lte = __lookup_resource(table, hash);
+ if (!lte && !is_zero_hash(hash)) {
+ ERROR("Could not find lookup table entry for stream "
+ "%u of dentry `%s'", i, dentry->full_path_utf8);
+ goto out;
+ }
+ }
+ }
+
+ /* Make sure there is only one un-named stream. */
+ unsigned num_unnamed_streams = 0;
+ unsigned unnamed_stream_idx;
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ const u8 *hash;
+ hash = dentry_stream_hash_unresolved(dentry, i);
+ if (dentry_stream_name_len(dentry, i) && !is_zero_hash(hash)) {
+ num_unnamed_streams++;
+ unnamed_stream_idx = i;
+ }
+ }
+ if (num_unnamed_streams > 1) {
+ ERROR("Dentry `%s' has multiple (%u) un-named streams",
+ dentry->full_path_utf8, num_unnamed_streams);
+ goto out;
+ }
+
+#if 0
+ /* Check timestamps */
+ if (dentry->last_access_time < dentry->creation_time ||
+ dentry->last_write_time < dentry->creation_time) {
+ WARNING("Dentry `%s' was created after it was last accessed or "
+ "written to", dentry->full_path_utf8);
+ }
+#endif
+
+ ret = 0;
+out:
+ return ret;
+}
+
/*
* Writes a WIM dentry to an output buffer.
*
extern int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
u64 offset, struct dentry *dentry);
+extern int verify_dentry(struct dentry *dentry, void *wim);
+
extern int read_dentry_tree(const u8 metadata_resource[],
u64 metadata_resource_len, struct dentry *dentry);
return dentry->ads_entries[stream_idx - 1].hash;
}
+static inline unsigned dentry_stream_name_len(const struct dentry *dentry,
+ unsigned stream_idx)
+{
+ wimlib_assert(stream_idx <= dentry->num_ads);
+ if (stream_idx == 0)
+ return dentry->file_name_len;
+ else
+ return dentry->ads_entries[stream_idx - 1].stream_name_len;
+}
+
static inline const u8 *dentry_stream_hash_resolved(const struct dentry *dentry,
unsigned stream_idx)
{
if (!fp) {
ERROR_WITH_ERRNO("Failed to open the file "
"`%s'", lte->file_on_disk);
+ return WIMLIB_ERR_OPEN;
}
}
ret = read_uncompressed_resource(fp, offset, size, buf);
*
* @return: Zero on success, nonzero on failure.
*/
-int read_metadata_resource(FILE *fp, int wim_ctype, struct image_metadata *imd)
+int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
{
u8 *buf;
int ctype;
u32 dentry_offset;
int ret;
struct dentry *dentry;
- struct wim_security_data *sd;
struct link_group_table *lgt;
const struct lookup_table_entry *metadata_lte;
u64 metadata_len;
* and if successful, go ahead and calculate the offset in the metadata
* resource of the root dentry. */
- ret = read_security_data(buf, metadata_len, &sd);
+ ret = read_security_data(buf, metadata_len, &imd->security_data);
if (ret != 0)
goto out_free_buf;
ret = link_groups_free_duplicate_data(lgt);
if (ret != 0)
goto out_free_lgt;
+
+ DEBUG("Running miscellaneous verifications on the dentry tree");
+ ret = for_dentry_in_tree(dentry, verify_dentry, w);
+ if (ret != 0)
+ goto out_free_lgt;
+
DEBUG("Done reading image metadata");
imd->lgt = lgt;
- imd->security_data = sd;
imd->root_dentry = dentry;
goto out_free_buf;
out_free_lgt:
out_free_dentry_tree:
free_dentry_tree(dentry, NULL);
out_free_security_data:
- free_security_data(sd);
+ free_security_data(imd->security_data);
+ imd->security_data = NULL;
out_free_buf:
FREE(buf);
return ret;
p = get_u32(p, &sd->total_length);
p = get_u32(p, &sd->num_entries);
+ if (sd->num_entries > 0x7fffffff) {
+ ERROR("Security data has too many entries!");
+ ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
+ goto out_free_sd;
+ }
+
/* Verify the listed total length of the security data is big enough to
* include the sizes array, verify that the file data is big enough to
* include it as well, then allocate the array of sizes.
ERROR("Security data total length (%u) is bigger than the "
"metadata resource length (%"PRIu64")",
sd->total_length, metadata_resource_len);
- ret = WIMLIB_ERR_INVALID_RESOURCE_SIZE;
+ ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
goto out_free_sd;
}
ERROR("Security data total length of %u is too short because "
"there must be at least %"PRIu64" bytes of security data",
sd->total_length, 8 + sizes_size);
- ret = WIMLIB_ERR_INVALID_RESOURCE_SIZE;
+ ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
goto out_free_sd;
}
sd->sizes = MALLOC(sizes_size);
ERROR("Security data total length of %u is too short "
"because there are at least %"PRIu64" bytes of "
"security data", sd->total_length, total_len);
- ret = WIMLIB_ERR_INVALID_RESOURCE_SIZE;
+ ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
goto out_free_sd;
}
sd->descriptors[i] = MALLOC(sd->sizes[i]);
"lookup table entry:");
print_lookup_table_entry(imd->metadata_lte);
#endif
- return read_metadata_resource(w->fp,
- wimlib_get_compression_type(w),
- imd);
+ return read_metadata_resource(w, imd);
}
}
* that wimlib writes, currently), it will be 8 bytes. */
u32 total_length;
- /* The number of security descriptors in the array @descriptors, below. */
- u32 num_entries;
+ /* The number of security descriptors in the array @descriptors, below.
+ * It is really an unsigned int, but it must fit into an int because the
+ * security ID's are signed. (Not like you would ever have more than a
+ * few hundred security descriptors anyway). */
+ int32_t num_entries;
/* Array of sizes of the descriptors in the array @descriptors. */
u64 *sizes;
extern int extract_full_wim_resource_to_fd(const struct lookup_table_entry *lte,
int fd);
-extern int read_metadata_resource(FILE *fp, int wim_ctype,
+extern int read_metadata_resource(WIMStruct *w,
struct image_metadata *image_metadata);
fi
echo "Testing appending directory containing unreadable file (should generate errors)"
mkdir -p dir3
-touch dir3/file
+echo 1 > dir3/file
chmod -r dir3/file
if imagex append dir3 dir.wim; then
error "Incorrectly succeeded in capturing directory with unreadable file"