From: Joanne Koong <joannelkoong@xxxxxxxxx> This fixes two things in bpf_local_storage_update: 1) A memory leak where if bpf_selem_alloc is called right before we acquire the spinlock and we hit the case where we can copy the new value into old_sdata directly, we need to free the selem allocation and uncharge the memory before we return. This was reported by the kernel test robot. 2) A charge leak where if bpf_selem_alloc is called right before we acquire the spinlock and we hit the case where old_sdata exists and we need to unlink the old selem, we need to make sure the old selem gets uncharged. Fixes: b00fa38a9c1c ("bpf: Enable non-atomic allocations in local storage") Reported-by: kernel test robot <lkp@xxxxxxxxx> Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx> --- kernel/bpf/bpf_local_storage.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c index 01aa2b51ec4d..2d33af0368ba 100644 --- a/kernel/bpf/bpf_local_storage.c +++ b/kernel/bpf/bpf_local_storage.c @@ -435,8 +435,12 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap, if (old_sdata && (map_flags & BPF_F_LOCK)) { copy_map_value_locked(&smap->map, old_sdata->data, value, false); - selem = SELEM(old_sdata); - goto unlock; + raw_spin_unlock_irqrestore(&local_storage->lock, flags); + if (selem) { + mem_uncharge(smap, owner, smap->elem_size); + kfree(selem); + } + return old_sdata; } if (gfp_flags != GFP_KERNEL) { @@ -466,10 +470,9 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap, if (old_sdata) { bpf_selem_unlink_map(SELEM(old_sdata)); bpf_selem_unlink_storage_nolock(local_storage, SELEM(old_sdata), - false); + gfp_flags == GFP_KERNEL); } -unlock: raw_spin_unlock_irqrestore(&local_storage->lock, flags); return SDATA(selem); -- 2.30.2