btrfs: convert btrfs_transaction.use_count from atomic_t to refcount_t
refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova <elena.reshetova@intel.com> Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com> Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: David Windsor <dwindsor@gmail.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Родитель
140475ae4a
Коммит
9b64f57ddf
|
@ -4615,7 +4615,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info)
|
||||||
t = list_first_entry(&fs_info->trans_list,
|
t = list_first_entry(&fs_info->trans_list,
|
||||||
struct btrfs_transaction, list);
|
struct btrfs_transaction, list);
|
||||||
if (t->state >= TRANS_STATE_COMMIT_START) {
|
if (t->state >= TRANS_STATE_COMMIT_START) {
|
||||||
atomic_inc(&t->use_count);
|
refcount_inc(&t->use_count);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
btrfs_wait_for_commit(fs_info, t->transid);
|
btrfs_wait_for_commit(fs_info, t->transid);
|
||||||
btrfs_put_transaction(t);
|
btrfs_put_transaction(t);
|
||||||
|
|
|
@ -10850,7 +10850,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
|
||||||
spin_lock(&fs_info->trans_lock);
|
spin_lock(&fs_info->trans_lock);
|
||||||
trans = fs_info->running_transaction;
|
trans = fs_info->running_transaction;
|
||||||
if (trans)
|
if (trans)
|
||||||
atomic_inc(&trans->use_count);
|
refcount_inc(&trans->use_count);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
|
|
||||||
ret = find_free_dev_extent_start(trans, device, minlen, start,
|
ret = find_free_dev_extent_start(trans, device, minlen, start,
|
||||||
|
|
|
@ -623,7 +623,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
|
||||||
spin_lock(&fs_info->trans_lock);
|
spin_lock(&fs_info->trans_lock);
|
||||||
trans = fs_info->running_transaction;
|
trans = fs_info->running_transaction;
|
||||||
if (trans)
|
if (trans)
|
||||||
atomic_inc(&trans->use_count);
|
refcount_inc(&trans->use_count);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
|
|
||||||
ASSERT(trans);
|
ASSERT(trans);
|
||||||
|
|
|
@ -60,8 +60,8 @@ static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
|
||||||
|
|
||||||
void btrfs_put_transaction(struct btrfs_transaction *transaction)
|
void btrfs_put_transaction(struct btrfs_transaction *transaction)
|
||||||
{
|
{
|
||||||
WARN_ON(atomic_read(&transaction->use_count) == 0);
|
WARN_ON(refcount_read(&transaction->use_count) == 0);
|
||||||
if (atomic_dec_and_test(&transaction->use_count)) {
|
if (refcount_dec_and_test(&transaction->use_count)) {
|
||||||
BUG_ON(!list_empty(&transaction->list));
|
BUG_ON(!list_empty(&transaction->list));
|
||||||
WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
|
WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
|
||||||
if (transaction->delayed_refs.pending_csums)
|
if (transaction->delayed_refs.pending_csums)
|
||||||
|
@ -207,7 +207,7 @@ loop:
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
atomic_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
atomic_inc(&cur_trans->num_writers);
|
atomic_inc(&cur_trans->num_writers);
|
||||||
extwriter_counter_inc(cur_trans, type);
|
extwriter_counter_inc(cur_trans, type);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
|
@ -257,7 +257,7 @@ loop:
|
||||||
* One for this trans handle, one so it will live on until we
|
* One for this trans handle, one so it will live on until we
|
||||||
* commit the transaction.
|
* commit the transaction.
|
||||||
*/
|
*/
|
||||||
atomic_set(&cur_trans->use_count, 2);
|
refcount_set(&cur_trans->use_count, 2);
|
||||||
atomic_set(&cur_trans->pending_ordered, 0);
|
atomic_set(&cur_trans->pending_ordered, 0);
|
||||||
cur_trans->flags = 0;
|
cur_trans->flags = 0;
|
||||||
cur_trans->start_time = get_seconds();
|
cur_trans->start_time = get_seconds();
|
||||||
|
@ -432,7 +432,7 @@ static void wait_current_trans(struct btrfs_fs_info *fs_info)
|
||||||
spin_lock(&fs_info->trans_lock);
|
spin_lock(&fs_info->trans_lock);
|
||||||
cur_trans = fs_info->running_transaction;
|
cur_trans = fs_info->running_transaction;
|
||||||
if (cur_trans && is_transaction_blocked(cur_trans)) {
|
if (cur_trans && is_transaction_blocked(cur_trans)) {
|
||||||
atomic_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
|
|
||||||
wait_event(fs_info->transaction_wait,
|
wait_event(fs_info->transaction_wait,
|
||||||
|
@ -744,7 +744,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
|
||||||
list_for_each_entry(t, &fs_info->trans_list, list) {
|
list_for_each_entry(t, &fs_info->trans_list, list) {
|
||||||
if (t->transid == transid) {
|
if (t->transid == transid) {
|
||||||
cur_trans = t;
|
cur_trans = t;
|
||||||
atomic_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -773,7 +773,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
|
||||||
if (t->state == TRANS_STATE_COMPLETED)
|
if (t->state == TRANS_STATE_COMPLETED)
|
||||||
break;
|
break;
|
||||||
cur_trans = t;
|
cur_trans = t;
|
||||||
atomic_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1839,7 +1839,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
/* take transaction reference */
|
/* take transaction reference */
|
||||||
cur_trans = trans->transaction;
|
cur_trans = trans->transaction;
|
||||||
atomic_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
|
|
||||||
btrfs_end_transaction(trans);
|
btrfs_end_transaction(trans);
|
||||||
|
|
||||||
|
@ -2015,7 +2015,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
|
||||||
spin_lock(&fs_info->trans_lock);
|
spin_lock(&fs_info->trans_lock);
|
||||||
if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
|
if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
atomic_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
ret = btrfs_end_transaction(trans);
|
ret = btrfs_end_transaction(trans);
|
||||||
|
|
||||||
wait_for_commit(cur_trans);
|
wait_for_commit(cur_trans);
|
||||||
|
@ -2035,7 +2035,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
|
||||||
prev_trans = list_entry(cur_trans->list.prev,
|
prev_trans = list_entry(cur_trans->list.prev,
|
||||||
struct btrfs_transaction, list);
|
struct btrfs_transaction, list);
|
||||||
if (prev_trans->state != TRANS_STATE_COMPLETED) {
|
if (prev_trans->state != TRANS_STATE_COMPLETED) {
|
||||||
atomic_inc(&prev_trans->use_count);
|
refcount_inc(&prev_trans->use_count);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
|
|
||||||
wait_for_commit(prev_trans);
|
wait_for_commit(prev_trans);
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
#ifndef __BTRFS_TRANSACTION__
|
#ifndef __BTRFS_TRANSACTION__
|
||||||
#define __BTRFS_TRANSACTION__
|
#define __BTRFS_TRANSACTION__
|
||||||
|
|
||||||
|
#include <linux/refcount.h>
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "delayed-ref.h"
|
#include "delayed-ref.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
|
@ -49,7 +51,7 @@ struct btrfs_transaction {
|
||||||
* transaction can end
|
* transaction can end
|
||||||
*/
|
*/
|
||||||
atomic_t num_writers;
|
atomic_t num_writers;
|
||||||
atomic_t use_count;
|
refcount_t use_count;
|
||||||
atomic_t pending_ordered;
|
atomic_t pending_ordered;
|
||||||
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче