Skip to content

Commit 537cf4e

Browse files
magnus-karlssonborkmann
authored andcommitted
xsk: Fix umem cleanup bug at socket destruct
Fix a bug that is triggered when a partially setup socket is destroyed. For a fully setup socket, a socket that has been bound to a device, the cleanup of the umem is performed at the end of the buffer pool's cleanup work queue item. This has to be performed in a work queue, and not in RCU cleanup, as it is doing a vunmap that cannot execute in interrupt context. However, when a socket has only been partially set up so that a umem has been created but the buffer pool has not, the code erroneously directly calls the umem cleanup function instead of using a work queue, and this leads to a BUG_ON() in vunmap(). As there in this case is no buffer pool, we cannot use its work queue, so we need to introduce a work queue for the umem and schedule this for the cleanup. So in the case there is no pool, we are going to use the umem's own work queue to schedule the cleanup. But if there is a pool, the cleanup of the umem is still being performed by the pool's work queue, as it is important that the umem is cleaned up after the pool. Fixes: e5e1a4b ("xsk: Fix possible memory leak at socket close") Reported-by: Marek Majtyka <[email protected]> Signed-off-by: Magnus Karlsson <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Tested-by: Marek Majtyka <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 6200d5c commit 537cf4e

File tree

5 files changed

+20
-6
lines changed

5 files changed

+20
-6
lines changed

include/net/xdp_sock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct xdp_umem {
3131
struct page **pgs;
3232
int id;
3333
struct list_head xsk_dma_list;
34+
struct work_struct work;
3435
};
3536

3637
struct xsk_map {

net/xdp/xdp_umem.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,31 @@ static void xdp_umem_release(struct xdp_umem *umem)
6666
kfree(umem);
6767
}
6868

69+
static void xdp_umem_release_deferred(struct work_struct *work)
70+
{
71+
struct xdp_umem *umem = container_of(work, struct xdp_umem, work);
72+
73+
xdp_umem_release(umem);
74+
}
75+
6976
void xdp_get_umem(struct xdp_umem *umem)
7077
{
7178
refcount_inc(&umem->users);
7279
}
7380

74-
void xdp_put_umem(struct xdp_umem *umem)
81+
void xdp_put_umem(struct xdp_umem *umem, bool defer_cleanup)
7582
{
7683
if (!umem)
7784
return;
7885

79-
if (refcount_dec_and_test(&umem->users))
80-
xdp_umem_release(umem);
86+
if (refcount_dec_and_test(&umem->users)) {
87+
if (defer_cleanup) {
88+
INIT_WORK(&umem->work, xdp_umem_release_deferred);
89+
schedule_work(&umem->work);
90+
} else {
91+
xdp_umem_release(umem);
92+
}
93+
}
8194
}
8295

8396
static int xdp_umem_pin_pages(struct xdp_umem *umem, unsigned long address)

net/xdp/xdp_umem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <net/xdp_sock_drv.h>
1010

1111
void xdp_get_umem(struct xdp_umem *umem);
12-
void xdp_put_umem(struct xdp_umem *umem);
12+
void xdp_put_umem(struct xdp_umem *umem, bool defer_cleanup);
1313
struct xdp_umem *xdp_umem_create(struct xdp_umem_reg *mr);
1414

1515
#endif /* XDP_UMEM_H_ */

net/xdp/xsk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ static void xsk_destruct(struct sock *sk)
11471147
return;
11481148

11491149
if (!xp_put_pool(xs->pool))
1150-
xdp_put_umem(xs->umem);
1150+
xdp_put_umem(xs->umem, !xs->pool);
11511151

11521152
sk_refcnt_debug_dec(sk);
11531153
}

net/xdp/xsk_buff_pool.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ static void xp_release_deferred(struct work_struct *work)
242242
pool->cq = NULL;
243243
}
244244

245-
xdp_put_umem(pool->umem);
245+
xdp_put_umem(pool->umem, false);
246246
xp_destroy(pool);
247247
}
248248

0 commit comments

Comments
 (0)