/* Creates and appends a 'struct wim_image_metadata' for an empty image. * * The resulting image will be the last in the WIM, so its index will be * the new value of wim->hdr.image_count. */ static int add_empty_image_metadata(WIMStruct *wim) { int ret; struct wim_lookup_table_entry *metadata_lte; struct wim_security_data *sd; struct wim_image_metadata *imd; /* Create lookup table entry for this metadata resource (for now really * just a dummy entry). */ ret = WIMLIB_ERR_NOMEM; metadata_lte = new_lookup_table_entry(); if (!metadata_lte) goto out; metadata_lte->flags = WIM_RESHDR_FLAG_METADATA; metadata_lte->unhashed = 1; /* Create empty security data (no security descriptors). */ sd = new_wim_security_data(); if (!sd) goto out_free_metadata_lte; imd = new_image_metadata(); if (!imd) goto out_free_security_data; /* A NULL root_dentry indicates a completely empty image, without even a * root directory. */ imd->root_dentry = NULL; imd->metadata_lte = metadata_lte; imd->security_data = sd; imd->modified = 1; /* Append as next image index. */ ret = append_image_metadata(wim, imd); if (ret) put_image_metadata(imd, NULL); goto out; out_free_security_data: free_wim_security_data(sd); out_free_metadata_lte: free_lookup_table_entry(metadata_lte); out: return ret; }
/* * Reads the security data from the metadata resource of a WIM image. * * @buf * Buffer containing an uncompressed WIM metadata resource. * @buf_len * Length of the uncompressed metadata resource, in bytes. * @sd_ret * On success, a pointer to the resulting security data structure will be * returned here. * * Note: There is no `offset' argument because the security data is located at * the beginning of the metadata resource. * * Return values: * WIMLIB_ERR_SUCCESS (0) * WIMLIB_ERR_INVALID_METADATA_RESOURCE * WIMLIB_ERR_NOMEM */ int read_wim_security_data(const u8 *buf, size_t buf_len, struct wim_security_data **sd_ret) { struct wim_security_data *sd; int ret; u64 total_len; u64 sizes_size; u64 size_no_descriptors; const struct wim_security_data_disk *sd_disk; const u8 *p; if (buf_len < 8) return WIMLIB_ERR_INVALID_METADATA_RESOURCE; sd = new_wim_security_data(); if (!sd) goto out_of_memory; sd_disk = (const struct wim_security_data_disk *)buf; sd->total_length = le32_to_cpu(sd_disk->total_length); sd->num_entries = le32_to_cpu(sd_disk->num_entries); DEBUG("Reading security data: num_entries=%u, total_length=%u", sd->num_entries, sd->total_length); /* Length field of 0 is a special case that really means length * of 8. */ if (sd->total_length == 0) sd->total_length = 8; /* The security_id field of each dentry is a signed 32-bit integer, so * the possible indices into the security descriptors table are 0 * through 0x7fffffff. Which means 0x80000000 security descriptors * maximum. Not like you should ever have anywhere close to that many * security descriptors! */ if (sd->num_entries > 0x80000000) goto out_invalid_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. * * Note: The total length of the security data must fit in a 32-bit * integer, even though each security descriptor size is a 64-bit * integer. This is stupid, and we need to be careful not to actually * let the security descriptor sizes be over 0xffffffff. */ if (sd->total_length > buf_len) goto out_invalid_sd; sizes_size = (u64)sd->num_entries * sizeof(u64); size_no_descriptors = 8 + sizes_size; if (size_no_descriptors > sd->total_length) goto out_invalid_sd; total_len = size_no_descriptors; /* Return immediately if no security descriptors. */ if (sd->num_entries == 0) goto out_align_total_length; /* Allocate a new buffer for the sizes array */ sd->sizes = MALLOC(sizes_size); if (!sd->sizes) goto out_of_memory; /* Copy the sizes array into the new buffer */ for (u32 i = 0; i < sd->num_entries; i++) { sd->sizes[i] = le64_to_cpu(sd_disk->sizes[i]); if (sd->sizes[i] > 0xffffffff) goto out_invalid_sd; } p = (const u8*)sd_disk + size_no_descriptors; /* Allocate the array of pointers to the security descriptors, then read * them into separate buffers. */ sd->descriptors = CALLOC(sd->num_entries, sizeof(sd->descriptors[0])); if (!sd->descriptors) goto out_of_memory; for (u32 i = 0; i < sd->num_entries; i++) { if (sd->sizes[i] == 0) continue; total_len += sd->sizes[i]; if (total_len > (u64)sd->total_length) goto out_invalid_sd; sd->descriptors[i] = memdup(p, sd->sizes[i]); if (!sd->descriptors[i]) goto out_of_memory; p += sd->sizes[i]; } out_align_total_length: total_len = (total_len + 7) & ~7; sd->total_length = (sd->total_length + 7) & ~7; if (total_len != sd->total_length) { WARNING("Expected WIM security data total length of " "%u bytes, but calculated %u bytes", sd->total_length, (unsigned)total_len); } *sd_ret = sd; ret = 0; goto out; out_invalid_sd: ERROR("WIM security data is invalid!"); ret = WIMLIB_ERR_INVALID_METADATA_RESOURCE; goto out_free_sd; out_of_memory: ERROR("Out of memory while reading WIM security data!"); ret = WIMLIB_ERR_NOMEM; out_free_sd: free_wim_security_data(sd); out: return ret; }