From 5afde6175219bb6ec45f49aba2bde813e8d6231a Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Fri, 24 Feb 2017 15:14:56 +1100 Subject: util/disk_cache: add support for detecting corrupt cache entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V2: fix pointer increments for writing/reading crc Acked-by: Marek Olšák Reviewed-by: Grigori Goronzy --- src/util/disk_cache.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/util/disk_cache.c b/src/util/disk_cache.c index f5e114513e0..f8e994853c1 100644 --- a/src/util/disk_cache.c +++ b/src/util/disk_cache.c @@ -38,6 +38,7 @@ #include #include +#include "util/crc32.h" #include "util/u_atomic.h" #include "util/mesa-sha1.h" #include "util/ralloc.h" @@ -709,6 +710,19 @@ disk_cache_put(struct disk_cache *cache, if (*cache->size + size > cache->max_size) evict_random_item(cache); + /* Create CRC of the data and store at the start of the file. We will + * read this when restoring the cache and use it to check for corruption. + */ + uint32_t crc32 = util_hash_crc32(data, size); + size_t crc_size = sizeof(crc32); + for (len = 0; len < crc_size; len += ret) { + ret = write(fd, ((uint8_t *) &crc32) + len, crc_size - len); + if (ret == -1) { + unlink(filename_tmp); + goto done; + } + } + /* Now, finally, write out the contents to the temporary file, then * rename them atomically to the destination filename, and also * perform an atomic increment of the total cache size. @@ -723,6 +737,7 @@ disk_cache_put(struct disk_cache *cache, rename(filename_tmp, filename); + size += crc_size; p_atomic_add(cache->size, size); done: @@ -765,17 +780,33 @@ disk_cache_get(struct disk_cache *cache, cache_key key, size_t *size) if (data == NULL) goto fail; - for (len = 0; len < sb.st_size; len += ret) { - ret = read(fd, data + len, sb.st_size - len); + /* Load the CRC that was created when the file was written. */ + uint32_t crc32; + size_t crc_size = sizeof(crc32); + assert(sb.st_size > crc_size); + for (len = 0; len < crc_size; len += ret) { + ret = read(fd, ((uint8_t *) &crc32) + len, crc_size - len); if (ret == -1) goto fail; } + /* Load the actual cache data. */ + size_t cache_data_size = sb.st_size - crc_size; + for (len = 0; len < cache_data_size; len += ret) { + ret = read(fd, data + len, cache_data_size - len); + if (ret == -1) + goto fail; + } + + /* Check the data for corruption */ + if (crc32 != util_hash_crc32(data, cache_data_size)) + goto fail; + free(filename); close(fd); if (size) - *size = sb.st_size; + *size = cache_data_size; return data; -- cgit v1.2.3