summaryrefslogtreecommitdiff
path: root/drivers/md/dm-pcache/cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-pcache/cache.h')
-rw-r--r--drivers/md/dm-pcache/cache.h42
1 files changed, 40 insertions, 2 deletions
diff --git a/drivers/md/dm-pcache/cache.h b/drivers/md/dm-pcache/cache.h
index 27613b56be54..021292c43677 100644
--- a/drivers/md/dm-pcache/cache.h
+++ b/drivers/md/dm-pcache/cache.h
@@ -180,6 +180,7 @@ struct pcache_cache {
u32 advance;
int ret;
} writeback_ctx;
+ atomic_t writeback_errors;
char gc_kset_onmedia_buf[PCACHE_KSET_ONMEDIA_SIZE_MAX];
struct delayed_work gc_work;
@@ -273,7 +274,7 @@ struct pcache_cache_subtree_walk_ctx {
struct list_head *submit_req_list;
/*
- * |--------| key_tmp
+ * |--------| key_tmp
* |====| key
*/
int (*before)(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
@@ -281,7 +282,7 @@ struct pcache_cache_subtree_walk_ctx {
/*
* |----------| key_tmp
- * |=====| key
+ * |=====| key
*/
int (*after)(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
struct pcache_cache_subtree_walk_ctx *ctx);
@@ -421,6 +422,20 @@ static inline bool cache_seg_is_ctrl_seg(u32 cache_seg_id)
}
/**
+ * cache_seg_id_valid - Validate a cache segment id read from the cache device.
+ * @cache: Pointer to the pcache_cache structure.
+ * @cache_seg_id: Segment id decoded from on-media metadata.
+ *
+ * On-media segment ids are only protected by a CRC, which an attacker who can
+ * format the cache device computes over their chosen value. Reject any id that
+ * would index cache->segments[] out of bounds before it is dereferenced.
+ */
+static inline bool cache_seg_id_valid(struct pcache_cache *cache, u32 cache_seg_id)
+{
+ return cache_seg_id < cache->cache_info.n_segs;
+}
+
+/**
* cache_key_cutfront - Cuts a specified length from the front of a cache key.
* @key: Pointer to pcache_cache_key structure.
* @cut_len: Length to cut from the front.
@@ -491,6 +506,27 @@ static inline u32 cache_key_data_crc(struct pcache_cache_key *key)
return crc32c(PCACHE_CRC_SEED, data, key->len);
}
+/**
+ * kset_onmedia_valid - Validate a kset header read from the cache device.
+ * @kset_onmedia: Pointer to the kset copied from on-media metadata.
+ *
+ * The magic and CRC are attacker-computable (fixed public seed). A non-last
+ * kset stores key_num keys inline, and cache_kset_crc() and the replay loop
+ * read struct_size(.., data, key_num) bytes from a buffer sized for
+ * PCACHE_KSET_KEYS_MAX keys, so key_num must be bounded before any such use.
+ */
+static inline bool kset_onmedia_valid(struct pcache_cache_kset_onmedia *kset_onmedia)
+{
+ if (kset_onmedia->magic != PCACHE_KSET_MAGIC)
+ return false;
+
+ if (!(kset_onmedia->flags & PCACHE_KSET_FLAGS_LAST) &&
+ kset_onmedia->key_num > PCACHE_KSET_KEYS_MAX)
+ return false;
+
+ return true;
+}
+
static inline u32 cache_kset_crc(struct pcache_cache_kset_onmedia *kset_onmedia)
{
u32 crc_size;
@@ -630,6 +666,8 @@ static inline int cache_decode_dirty_tail(struct pcache_cache *cache)
&cache->dirty_tail_index);
}
+int cache_verify_dirty_tail(struct pcache_cache *cache);
+
int pcache_cache_init(void);
void pcache_cache_exit(void);
#endif /* _PCACHE_CACHE_H */