Skip to content

Commit 4f96abd

Browse files
magnus-karlssonkernel-patches-bot
authored andcommitted
xsk: fix possible memory leak at socket close
Fix a possible memory leak at xsk socket close that is caused by the refcounting of the umem object being wrong. The reference count of the umem was decremented only after the pool had been freed. Note that if the buffer pool is destroyed, it is important that the umem is destroyed after the pool, otherwise the umem would disappear while the driver is still running. And as the buffer pool needs to be destroyed in a work queue, the umem is also (if its refcount reaches zero) destroyed after the buffer pool in that same work queue. What was missing is that the refcount also needs to be decremented when the pool is not freed and when the pool has not even been created. The first case happens when the refcount of the pool is higher than 1, i.e. it is still being used by some other socket using the same device and queue id. In this case, it is safe to decrement the refcount of the umem outside of the work queue as the umem will never be freed because the refcount of the umem is always greater than or equal to the refcount of the buffer pool. The second case is if the buffer pool has not been created yet, i.e. the socket was closed before it was bound but after the umem was created. In this case, it is safe to destroy the umem outside of the work queue, since there is no pool that can use it by definition. Fixes: 1c1efc2 ("xsk: Create and free buffer pool independently from umem") Reported-by: [email protected] Signed-off-by: Magnus Karlsson <[email protected]>
1 parent a06d5ac commit 4f96abd

File tree

3 files changed

+8
-4
lines changed

3 files changed

+8
-4
lines changed

include/net/xsk_buff_pool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ int xp_assign_dev_shared(struct xsk_buff_pool *pool, struct xdp_umem *umem,
8686
void xp_destroy(struct xsk_buff_pool *pool);
8787
void xp_release(struct xdp_buff_xsk *xskb);
8888
void xp_get_pool(struct xsk_buff_pool *pool);
89-
void xp_put_pool(struct xsk_buff_pool *pool);
89+
bool xp_put_pool(struct xsk_buff_pool *pool);
9090
void xp_clear_dev(struct xsk_buff_pool *pool);
9191
void xp_add_xsk(struct xsk_buff_pool *pool, struct xdp_sock *xs);
9292
void xp_del_xsk(struct xsk_buff_pool *pool, struct xdp_sock *xs);

net/xdp/xsk.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,8 @@ static void xsk_destruct(struct sock *sk)
11461146
if (!sock_flag(sk, SOCK_DEAD))
11471147
return;
11481148

1149-
xp_put_pool(xs->pool);
1149+
if (!xp_put_pool(xs->pool))
1150+
xdp_put_umem(xs->umem);
11501151

11511152
sk_refcnt_debug_dec(sk);
11521153
}

net/xdp/xsk_buff_pool.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,15 +251,18 @@ void xp_get_pool(struct xsk_buff_pool *pool)
251251
refcount_inc(&pool->users);
252252
}
253253

254-
void xp_put_pool(struct xsk_buff_pool *pool)
254+
bool xp_put_pool(struct xsk_buff_pool *pool)
255255
{
256256
if (!pool)
257-
return;
257+
return false;
258258

259259
if (refcount_dec_and_test(&pool->users)) {
260260
INIT_WORK(&pool->work, xp_release_deferred);
261261
schedule_work(&pool->work);
262+
return true;
262263
}
264+
265+
return false;
263266
}
264267

265268
static struct xsk_dma_map *xp_find_dma_map(struct xsk_buff_pool *pool)

0 commit comments

Comments
 (0)