]> wimlib.net Git - wimlib/blobdiff - src/integrity.c
integrity.c: correctly validate minimum integrity table size
[wimlib] / src / integrity.c
index ebde93066c572c5cfc60a0b5bfe709f78a109bd4..fc9b8859b53e632062821df0afa1682cec97d803 100644 (file)
@@ -7,22 +7,20 @@
  */
 
 /*
- * Copyright (C) 2012, 2013 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -44,7 +42,7 @@
  * information. */
 #define INTEGRITY_CHUNK_SIZE 10485760
 
-/* Only use a different chunk size for compatiblity with an existing integrity
+/* Only use a different chunk size for compatibility with an existing integrity
  * table if the chunk size is between these two numbers. */
 #define INTEGRITY_MIN_CHUNK_SIZE 4096
 #define INTEGRITY_MAX_CHUNK_SIZE 134217728
@@ -107,7 +105,7 @@ calculate_chunk_sha1(struct filedes *in_fd, size_t this_chunk_size,
  *     WIMLIB_ERR_READ
  *     WIMLIB_ERR_UNEXPECTED_END_OF_FILE
  */
-static int
+int
 read_integrity_table(WIMStruct *wim, u64 num_checked_bytes,
                     struct integrity_table **table_ret)
 {
@@ -115,10 +113,9 @@ read_integrity_table(WIMStruct *wim, u64 num_checked_bytes,
        struct integrity_table *table;
        int ret;
 
-       if (wim->hdr.integrity_table_reshdr.uncompressed_size < 8)
-               goto invalid;
-
-       DEBUG("Reading integrity table.");
+       STATIC_ASSERT(sizeof(struct integrity_table) == 12);
+       if (wim->hdr.integrity_table_reshdr.uncompressed_size < 12)
+               return WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
 
        ret = wim_reshdr_to_data(&wim->hdr.integrity_table_reshdr, wim, &buf);
        if (ret)
@@ -129,25 +126,17 @@ read_integrity_table(WIMStruct *wim, u64 num_checked_bytes,
        table->num_entries = le32_to_cpu(table->num_entries);
        table->chunk_size  = le32_to_cpu(table->chunk_size);
 
-       DEBUG("table->size = %u, table->num_entries = %u, "
-             "table->chunk_size = %u",
-             table->size, table->num_entries, table->chunk_size);
-
        if (table->size != wim->hdr.integrity_table_reshdr.uncompressed_size ||
            table->size != (u64)table->num_entries * SHA1_HASH_SIZE + 12 ||
            table->chunk_size == 0 ||
            table->num_entries != DIV_ROUND_UP(num_checked_bytes, table->chunk_size))
        {
                FREE(table);
-               goto invalid;
+               return WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
        }
 
        *table_ret = table;
        return 0;
-
-invalid:
-       ERROR("Integrity table is invalid");
-       return WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
 }
 
 /*
@@ -282,72 +271,45 @@ out_free_new_table:
  * chunks of the file).
  *
  * This function can optionally re-use entries from an older integrity table.
- * To do this, ensure that @wim->hdr.integrity_table_reshdr is the resource
- * header for the older table (note: this is an input-output parameter), and set
- * @old_lookup_table_end to the offset of the byte directly following the last
- * byte checked by the old table.  If the old integrity table is invalid or
- * cannot be read, a warning is printed and the integrity information is
- * re-calculated.
+ * To do this, specify old_blob_table_end and old_table.
+ *
+ * On success, @wim->out_hdr.integrity_table_reshdr will be filled in with
+ * information about the integrity table that was written.
  *
  * @wim:
  *     WIMStruct for the WIM file.  @wim->out_fd must be a seekable descriptor
  *     to the new WIM file, opened read-write, positioned at the location at
- *     which the integrity table is to be written.  Furthermore,
- *     @wim->hdr.integrity is expected to be a resource entry which will be set
- *     to the integrity table information on success.  In addition, if
- *     @old_lookup_table_end != 0, @wim->hdr.integrity must initially contain
- *     information about the old integrity table, and @wim->in_fd must be a
- *     seekable descriptor to the original WIM file opened for reading.
+ *     which the integrity table is to be written.
  *
- * @new_lookup_table_end:
- *     The offset of the byte directly following the lookup table in the WIM
+ * @new_blob_table_end:
+ *     The offset of the byte directly following the blob table in the WIM
  *     being written.
  *
- * @old_lookup_table_end:
- *     If nonzero, the offset of the byte directly following the old lookup
- *     table in the WIM.
+ * @old_blob_table_end:
+ *     If nonzero, the offset of the byte directly following the old blob table
+ *     in the WIM.
  *
- * Return values:
- *     WIMLIB_ERR_SUCCESS (0)
- *     WIMLIB_ERR_NOMEM
- *     WIMLIB_ERR_UNEXPECTED_END_OF_FILE
- *     WIMLIB_ERR_WRITE
+ * @old_table
+ *     Pointer to the old integrity table read into memory, or NULL if not
+ *     specified.
  */
 int
 write_integrity_table(WIMStruct *wim,
-                     off_t new_lookup_table_end,
-                     off_t old_lookup_table_end)
+                     off_t new_blob_table_end,
+                     off_t old_blob_table_end,
+                     struct integrity_table *old_table)
 {
-       struct integrity_table *old_table;
        struct integrity_table *new_table;
        int ret;
        u32 new_table_size;
 
-       DEBUG("Writing integrity table "
-             "(new_lookup_table_end=%"PRIu64", old_lookup_table_end=%"PRIu64")",
-             new_lookup_table_end, old_lookup_table_end);
-
-       wimlib_assert(old_lookup_table_end <= new_lookup_table_end);
-
-       old_table = NULL;
-       if (wim_has_integrity_table(wim) && old_lookup_table_end != 0) {
-               ret = read_integrity_table(wim,
-                                          old_lookup_table_end - WIM_HEADER_DISK_SIZE,
-                                          &old_table);
-               if (ret == WIMLIB_ERR_INVALID_INTEGRITY_TABLE) {
-                       WARNING("Old integrity table is invalid! "
-                               "Ignoring it");
-               } else if (ret != 0) {
-                       WARNING("Can't read old integrity table! "
-                               "Ignoring it");
-               }
-       }
+       wimlib_assert(old_blob_table_end <= new_blob_table_end);
 
-       ret = calculate_integrity_table(&wim->out_fd, new_lookup_table_end,
-                                       old_table, old_lookup_table_end,
+       ret = calculate_integrity_table(&wim->out_fd, new_blob_table_end,
+                                       old_table, old_blob_table_end,
                                        &new_table, wim->progfunc, wim->progctx);
        if (ret)
-               goto out_free_old_table;
+               return ret;
 
        new_table_size = new_table->size;
 
@@ -357,17 +319,14 @@ write_integrity_table(WIMStruct *wim,
 
        ret = write_wim_resource_from_buffer(new_table,
                                             new_table_size,
-                                            0,
+                                            false,
                                             &wim->out_fd,
                                             WIMLIB_COMPRESSION_TYPE_NONE,
                                             0,
-                                            &wim->hdr.integrity_table_reshdr,
+                                            &wim->out_hdr.integrity_table_reshdr,
                                             NULL,
                                             0);
        FREE(new_table);
-out_free_old_table:
-       FREE(old_table);
-       DEBUG("ret=%d", ret);
        return ret;
 }
 
@@ -384,7 +343,7 @@ out_free_old_table:
  *
  * @bytes_to_check:
  *     Number of bytes in the WIM that need to be checked (offset of end of the
- *     lookup table minus offset of end of the header).
+ *     blob table minus offset of end of the header).
  *
  * Returns:
  *     > 0 (WIMLIB_ERR_READ, WIMLIB_ERR_UNEXPECTED_END_OF_FILE) on error
@@ -468,22 +427,20 @@ check_wim_integrity(WIMStruct *wim)
        int ret;
        u64 bytes_to_check;
        struct integrity_table *table;
-       u64 end_lookup_table_offset;
+       u64 end_blob_table_offset;
 
-       if (!wim_has_integrity_table(wim)) {
-               DEBUG("No integrity information.");
+       if (!wim_has_integrity_table(wim))
                return WIM_INTEGRITY_NONEXISTENT;
-       }
 
-       end_lookup_table_offset = wim->hdr.lookup_table_reshdr.offset_in_wim +
-                                 wim->hdr.lookup_table_reshdr.size_in_wim;
+       end_blob_table_offset = wim->hdr.blob_table_reshdr.offset_in_wim +
+                               wim->hdr.blob_table_reshdr.size_in_wim;
 
-       if (end_lookup_table_offset < WIM_HEADER_DISK_SIZE) {
-               ERROR("WIM lookup table ends before WIM header ends!");
+       if (end_blob_table_offset < WIM_HEADER_DISK_SIZE) {
+               ERROR("WIM blob table ends before WIM header ends!");
                return WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
        }
 
-       bytes_to_check = end_lookup_table_offset - WIM_HEADER_DISK_SIZE;
+       bytes_to_check = end_blob_table_offset - WIM_HEADER_DISK_SIZE;
 
        ret = read_integrity_table(wim, bytes_to_check, &table);
        if (ret)