diff options
author | Elena Reshetova <elena.reshetova@intel.com> | 2017-10-20 03:37:37 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2017-10-24 15:09:51 -0400 |
commit | 6bdd079610d3a5de0f4eb78d8015bd530c291cd7 (patch) | |
tree | 82b65fc46466466ecaa8339e0d52126d8bcb4dab | |
parent | b0b4d7c6752a45c545bcdce647ccfa8fb27f0a06 (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.c | 9 |
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 | ||
102 | struct dm_cache_metadata { | 103 | struct 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 | ||
863 | void dm_cache_metadata_close(struct dm_cache_metadata *cmd) | 864 | void 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); |