aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElena Reshetova <elena.reshetova@intel.com>2017-10-20 03:37:37 -0400
committerMike Snitzer <snitzer@redhat.com>2017-10-24 15:09:51 -0400
commit6bdd079610d3a5de0f4eb78d8015bd530c291cd7 (patch)
tree82b65fc46466466ecaa8339e0d52126d8bcb4dab
parentb0b4d7c6752a45c545bcdce647ccfa8fb27f0a06 (diff)
dm cache: convert dm_cache_metadata.ref_count from atomic_t to refcount_t
atomic_t variables are currently used to implement reference counters with the following properties: - counter is initialized to 1 using atomic_set() - a resource is freed upon counter reaching zero - once counter reaches zero, its further increments aren't allowed - counter schema uses basic atomic operations (set, inc, inc_not_zero, dec_and_test, etc.) Such atomic variables should be converted to a newly provided refcount_t type and API that prevents accidental counter overflows and underflows. This is important since overflows and underflows can lead to use-after-free situation and be exploitable. The variable dm_cache_metadata.ref_count is used as pure reference counter. Convert it to refcount_t and fix up the operations. Suggested-by: Kees Cook <keescook@chromium.org> Reviewed-by: David Windsor <dwindsor@gmail.com> Reviewed-by: Hans Liljestrand <ishkamiel@gmail.com> Signed-off-by: Elena Reshetova <elena.reshetova@intel.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-rw-r--r--drivers/md/dm-cache-metadata.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 4a4e9c75fc4c..0d7212410e21 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -13,6 +13,7 @@
13#include "persistent-data/dm-transaction-manager.h" 13#include "persistent-data/dm-transaction-manager.h"
14 14
15#include <linux/device-mapper.h> 15#include <linux/device-mapper.h>
16#include <linux/refcount.h>
16 17
17/*----------------------------------------------------------------*/ 18/*----------------------------------------------------------------*/
18 19
@@ -100,7 +101,7 @@ struct cache_disk_superblock {
100} __packed; 101} __packed;
101 102
102struct dm_cache_metadata { 103struct dm_cache_metadata {
103 atomic_t ref_count; 104 refcount_t ref_count;
104 struct list_head list; 105 struct list_head list;
105 106
106 unsigned version; 107 unsigned version;
@@ -753,7 +754,7 @@ static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
753 } 754 }
754 755
755 cmd->version = metadata_version; 756 cmd->version = metadata_version;
756 atomic_set(&cmd->ref_count, 1); 757 refcount_set(&cmd->ref_count, 1);
757 init_rwsem(&cmd->root_lock); 758 init_rwsem(&cmd->root_lock);
758 cmd->bdev = bdev; 759 cmd->bdev = bdev;
759 cmd->data_block_size = data_block_size; 760 cmd->data_block_size = data_block_size;
@@ -791,7 +792,7 @@ static struct dm_cache_metadata *lookup(struct block_device *bdev)
791 792
792 list_for_each_entry(cmd, &table, list) 793 list_for_each_entry(cmd, &table, list)
793 if (cmd->bdev == bdev) { 794 if (cmd->bdev == bdev) {
794 atomic_inc(&cmd->ref_count); 795 refcount_inc(&cmd->ref_count);
795 return cmd; 796 return cmd;
796 } 797 }
797 798
@@ -862,7 +863,7 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
862 863
863void dm_cache_metadata_close(struct dm_cache_metadata *cmd) 864void dm_cache_metadata_close(struct dm_cache_metadata *cmd)
864{ 865{
865 if (atomic_dec_and_test(&cmd->ref_count)) { 866 if (refcount_dec_and_test(&cmd->ref_count)) {
866 mutex_lock(&table_lock); 867 mutex_lock(&table_lock);
867 list_del(&cmd->list); 868 list_del(&cmd->list);
868 mutex_unlock(&table_lock); 869 mutex_unlock(&table_lock);