mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
bcachefs: Fix alloc_req use after free
Now the alloc_req is allocated from the bump allocator, if there is reallocation, the memory of alloc_req would be frees, fix by delaying the reallocation to transaction restart, it has to restart anyway. Reported-by: syzbot+2887a13a5c387e616a68@syzkaller.appspotmail.com Signed-off-by: Alan Huang <mmpgouride@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
committed by
Kent Overstreet
parent
9b9a327009
commit
9b54efe66c
@@ -3216,25 +3216,32 @@ void *__bch2_trans_kmalloc(struct btree_trans *trans, size_t size, unsigned long
|
||||
mutex_unlock(&s->lock);
|
||||
}
|
||||
|
||||
if (trans->used_mempool) {
|
||||
if (trans->used_mempool || new_bytes > BTREE_TRANS_MEM_MAX) {
|
||||
EBUG_ON(trans->mem_bytes >= new_bytes);
|
||||
return ERR_PTR(-BCH_ERR_ENOMEM_trans_kmalloc);
|
||||
}
|
||||
|
||||
new_mem = krealloc(trans->mem, new_bytes, GFP_NOWAIT|__GFP_NOWARN);
|
||||
if (old_bytes) {
|
||||
trans->realloc_bytes_required = new_bytes;
|
||||
trace_and_count(c, trans_restart_mem_realloced, trans, _RET_IP_, new_bytes);
|
||||
return ERR_PTR(btree_trans_restart_ip(trans,
|
||||
BCH_ERR_transaction_restart_mem_realloced, _RET_IP_));
|
||||
}
|
||||
|
||||
EBUG_ON(trans->mem);
|
||||
|
||||
new_mem = kmalloc(new_bytes, GFP_NOWAIT|__GFP_NOWARN);
|
||||
if (unlikely(!new_mem)) {
|
||||
bch2_trans_unlock(trans);
|
||||
|
||||
new_mem = krealloc(trans->mem, new_bytes, GFP_KERNEL);
|
||||
new_mem = kmalloc(new_bytes, GFP_KERNEL);
|
||||
if (!new_mem && new_bytes <= BTREE_TRANS_MEM_MAX) {
|
||||
new_mem = mempool_alloc(&c->btree_trans_mem_pool, GFP_KERNEL);
|
||||
new_bytes = BTREE_TRANS_MEM_MAX;
|
||||
trans->used_mempool = true;
|
||||
kfree(trans->mem);
|
||||
}
|
||||
|
||||
if (!new_mem)
|
||||
return ERR_PTR(-BCH_ERR_ENOMEM_trans_kmalloc);
|
||||
EBUG_ON(!new_mem);
|
||||
|
||||
trans->mem = new_mem;
|
||||
trans->mem_bytes = new_bytes;
|
||||
@@ -3247,14 +3254,6 @@ void *__bch2_trans_kmalloc(struct btree_trans *trans, size_t size, unsigned long
|
||||
trans->mem = new_mem;
|
||||
trans->mem_bytes = new_bytes;
|
||||
|
||||
if (old_bytes) {
|
||||
trace_and_count(c, trans_restart_mem_realloced, trans, _RET_IP_, new_bytes);
|
||||
return ERR_PTR(btree_trans_restart_ip(trans,
|
||||
BCH_ERR_transaction_restart_mem_realloced, _RET_IP_));
|
||||
}
|
||||
|
||||
bch2_trans_kmalloc_trace(trans, size, ip);
|
||||
|
||||
p = trans->mem + trans->mem_top;
|
||||
trans->mem_top += size;
|
||||
memset(p, 0, size);
|
||||
@@ -3315,6 +3314,27 @@ u32 bch2_trans_begin(struct btree_trans *trans)
|
||||
trans->restart_count++;
|
||||
trans->mem_top = 0;
|
||||
|
||||
if (trans->restarted == BCH_ERR_transaction_restart_mem_realloced) {
|
||||
EBUG_ON(!trans->mem || !trans->mem_bytes);
|
||||
unsigned new_bytes = trans->realloc_bytes_required;
|
||||
void *new_mem = krealloc(trans->mem, new_bytes, GFP_NOWAIT|__GFP_NOWARN);
|
||||
if (unlikely(!new_mem)) {
|
||||
bch2_trans_unlock(trans);
|
||||
new_mem = krealloc(trans->mem, new_bytes, GFP_KERNEL);
|
||||
|
||||
EBUG_ON(new_bytes > BTREE_TRANS_MEM_MAX);
|
||||
|
||||
if (!new_mem) {
|
||||
new_mem = mempool_alloc(&trans->c->btree_trans_mem_pool, GFP_KERNEL);
|
||||
new_bytes = BTREE_TRANS_MEM_MAX;
|
||||
trans->used_mempool = true;
|
||||
kfree(trans->mem);
|
||||
}
|
||||
}
|
||||
trans->mem = new_mem;
|
||||
trans->mem_bytes = new_bytes;
|
||||
}
|
||||
|
||||
trans_for_each_path(trans, path, i) {
|
||||
path->should_be_locked = false;
|
||||
|
||||
|
||||
@@ -497,6 +497,7 @@ struct btree_trans {
|
||||
void *mem;
|
||||
unsigned mem_top;
|
||||
unsigned mem_bytes;
|
||||
unsigned realloc_bytes_required;
|
||||
#ifdef CONFIG_BCACHEFS_TRANS_KMALLOC_TRACE
|
||||
darray_trans_kmalloc_trace trans_kmalloc_trace;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user