AF_XDP Socket Creation Fixes
Subsystems (4)
v4 cover AF_XDP Socket Creation Fixes
This series fixes some issues around socket creation for AF_XDP.
Patch 1 fixes a potential NULL pointer dereference in xsk_socket__create_shared.
Patch 2 ensures that the umem passed to xsk_socket__create(_shared) remains unchanged in event of failure.
Patch 3 makes it possible for xsk_socket__create(_shared) to succeed even if the rx and tx XDP rings have already been set up by introducing a new fields to struct xsk_umem which represent the ring setup status for the xsk which shares the fd with the umem.
v3->v4:
* Reduced nesting in xsk_put_ctx as suggested by Alexei.
* Use bools instead of a u8 and flags to represent the ring setup status as suggested by Björn.
v2->v3:
* Instead of ignoring the return values of the setsockopt calls, introduce a new flag to determine whether or not to call them based on the ring setup status as suggested by Alexei.
v1->v2:
* Simplified restoring the _save pointers as suggested by Magnus.
* Fixed the condition which determines whether to unmap umem rings when socket create fails.
This series applies on commit 861de02e5f3f2a104eecc5af1d248cb7bf8c5f75
Ciara Loftus (3):
libbpf: ensure umem pointer is non-NULL before dereferencing
libbpf: restore umem state after socket create failure
libbpf: only create rx and tx XDP rings when necessary
tools/lib/bpf/xsk.c | 57 +++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 20 deletions(-)
Signature · 1 line
2.17.1
PATCH v4 1/3 libbpf: ensure umem pointer is non-NULL before dereferencing
Calls to xsk_socket__create dereference the umem to access the fill_save and comp_save pointers. Make sure the umem is non-NULL before doing this.
--- tools/lib/bpf/xsk.c | 3 +++ 1 file changed, 3 insertions(+)
tools/lib/bpf/xsk.c +3 -0
@@ -1019,6 +1019,9 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, struct xsk_ring_cons *rx, struct xsk_ring_prod *tx, const struct xsk_socket_config *usr_config) { + if (!umem) + return -EFAULT; + return xsk_socket__create_shared(xsk_ptr, ifname, queue_id, umem, rx, tx, umem->fill_save, umem->comp_save, usr_config);
Signature · 1 line
2.17.1
PATCH v4 2/3 libbpf: restore umem state after socket create failure
In reply to Ciara LoftusIf the call to xsk_socket__create fails, the user may want to retry the socket creation using the same umem. Ensure that the umem is in the same state on exit if the call fails by:
1. ensuring the umem _save pointers are unmodified.
2. not unmapping the set of umem rings that were set up with the umem during xsk_umem__create, since those maps existed before the call to xsk_socket__create and should remain in tact even in the event of failure.
--- tools/lib/bpf/xsk.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-)
tools/lib/bpf/xsk.c +23 -18
@@ -743,26 +743,30 @@ static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex,return NULL ; } -static void xsk_put_ctx (struct xsk_ctx *ctx) +static void xsk_put_ctx (struct xsk_ctx *ctx,bool unmap) {struct xsk_umem *umem = ctx->umem;struct xdp_mmap_offsets off;int err; -if (--ctx->refcount ==0 ) { - err =xsk_get_mmap_offsets (umem->fd, &off); -if (!err) { -munmap (ctx->fill->ring - off.fr.desc, - off.fr.desc + umem->config.fill_size * -sizeof (__u64)); -munmap (ctx->comp->ring - off.cr.desc, - off.cr.desc + umem->config.comp_size * -sizeof (__u64)); - } +if (--ctx->refcount) +return ; -list_del (&ctx->list); -free (ctx); - } +if (!unmap) + goto out_free; + + err =xsk_get_mmap_offsets (umem->fd, &off); +if (err) + goto out_free; + +munmap (ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size * +sizeof (__u64)); +munmap (ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size * +sizeof (__u64)); + +out_free: +list_del (&ctx->list); +free (ctx); } static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
@@ -797,8 +801,6 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,memcpy (ctx->ifname, ifname,IFNAMSIZ -1 ); ctx->ifname[IFNAMSIZ -1 ] ='\0' ; - umem->fill_save =NULL ; - umem->comp_save =NULL ; ctx->fill = fill; ctx->comp = comp;list_add (&ctx->list, &umem->ctx_list);
@@ -854,6 +856,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,struct xsk_socket *xsk;struct xsk_ctx *ctx;int err, ifindex; +bool unmap = umem->fill_save != fill;if (!umem || !xsk_ptr || !(rx || tx))return -EFAULT ;
@@ -994,6 +997,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, } *xsk_ptr = xsk; + umem->fill_save =NULL ; + umem->comp_save =NULL ;return 0 ; out_mmap_tx:
@@ -1005,7 +1010,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,munmap (rx_map, off.rx.desc + xsk->config.rx_size *sizeof (struct xdp_desc )); out_put_ctx: -xsk_put_ctx (ctx); +xsk_put_ctx (ctx, unmap); out_socket:if (--umem->refcount)close (xsk->fd);
@@ -1071,7 +1076,7 @@ void xsk_socket__delete(struct xsk_socket *xsk) } } -xsk_put_ctx (ctx); +xsk_put_ctx (ctx, true); umem->refcount--;/* Do not close an fd that also has an associated umem connected
Signature · 1 line
2.17.1
Re: [PATCH v4 bpf 2/3] libbpf: restore umem state after socket create failure
Quoted 76 lines · Ciara Loftus
If the call to
xsk_socket__createfails, the user may want to retry the socket creation using the same umem. Ensure that the umem is in the same state on exit if the call fails by:
1. ensuring the umem_savepointers are unmodified.
2. not unmapping the set of umem rings that were set up with the umem duringxsk_umem__create, since those maps existed before the call toxsk_socket__createand should remain in tact even in the event of failure.Fixes 2f6324a3937f ("libbpf: Support shared umems between queues and devices")Signed-off-by Ciara Loftus <[email protected]>--- tools/lib/bpf/xsk.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-)tools/lib/bpf/xsk.c +18
-16@@ -743,26 +743,30 @@ static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex,return NULL ; } -static void xsk_put_ctx (struct xsk_ctx *ctx) +static void xsk_put_ctx (struct xsk_ctx *ctx,bool unmap) {struct xsk_umem *umem = ctx->umem;struct xdp_mmap_offsets off;int err; -if (--ctx->refcount ==0 ) { - err =xsk_get_mmap_offsets (umem->fd, &off); -if (!err) { -munmap (ctx->fill->ring - off.fr.desc, - off.fr.desc + umem->config.fill_size * -sizeof (__u64)); -munmap (ctx->comp->ring - off.cr.desc, - off.cr.desc + umem->config.comp_size * -sizeof (__u64)); - } +if (--ctx->refcount) +return ; -list_del (&ctx->list); -free (ctx); - } +if (!unmap) + goto out_free; + + err =xsk_get_mmap_offsets (umem->fd, &off); +if (err) + goto out_free; + +munmap (ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size * +sizeof (__u64)); +munmap (ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size * +sizeof (__u64)); + +out_free: +list_del (&ctx->list); +free (ctx); } static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,@@ -797,8 +801,6 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,memcpy (ctx->ifname, ifname,IFNAMSIZ -1 ); ctx->ifname[IFNAMSIZ -1 ] ='\0' ; - umem->fill_save =NULL ; - umem->comp_save =NULL ; ctx->fill = fill; ctx->comp = comp;list_add (&ctx->list, &umem->ctx_list);
tools/lib/bpf/xsk.c int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, · line 860
Quoted 5 lines
tools/lib/bpf/xsk.c +1
-0@@ -854,6 +856,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,struct xsk_socket *xsk;struct xsk_ctx *ctx;int err, ifindex; +bool unmap = umem->fill_save != fill;
we are checking !umem only on the next line, so here it can be still NULL. Please send a fix, thanks.
Quoted 32 lines
tools/lib/bpf/xsk.c +4
-3if (!umem || !xsk_ptr || !(rx || tx))return -EFAULT ;@@ -994,6 +997,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, } *xsk_ptr = xsk; + umem->fill_save =NULL ; + umem->comp_save =NULL ;return 0 ; out_mmap_tx:@@ -1005,7 +1010,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,munmap (rx_map, off.rx.desc + xsk->config.rx_size *sizeof (struct xdp_desc )); out_put_ctx: -xsk_put_ctx (ctx); +xsk_put_ctx (ctx, unmap); out_socket:if (--umem->refcount)close (xsk->fd);@@ -1071,7 +1076,7 @@ void xsk_socket__delete(struct xsk_socket *xsk) } } -xsk_put_ctx (ctx); +xsk_put_ctx (ctx, true); umem->refcount--;/* Do not close an fd that also has an associated umem connected -- 2.17.1
RE: [PATCH v4 bpf 2/3] libbpf: restore umem state after socket create failure
Quoted 84 lines
Quoted 11 lines · Ciara Loftus
If the call to
xsk_socket__createfails, the user may want to retry the socket creation using the same umem. Ensure that the umem is in the same state on exit if the call fails by:
1. ensuring the umem_savepointers are unmodified.
2. not unmapping the set of umem rings that were set up with the umem duringxsk_umem__create, since those maps existed before the call toxsk_socket__createand should remain in tact even in the event of failure.Fixes 2f6324a3937f ("libbpf: Support shared umems between queues anddevices")
tools/lib/bpf/xsk.c static struct xsk_ctx *xsk_get_ctx(struct
Quoted 11 lines
Signed-off-by Ciara Loftus <[email protected]>--- tools/lib/bpf/xsk.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-)tools/lib/bpf/xsk.c +0
-0@@ -743,26 +743,30 @@ static struct xsk_ctx *xsk_get_ctx(struct
xsk_umem*umem, int ifindex,tools/lib/bpf/xsk.c static struct xsk_ctx *xsk_create_ctx(struct
Quoted 47 lines
tools/lib/bpf/xsk.c +11
-14return NULL ; } -static void xsk_put_ctx (struct xsk_ctx *ctx) +static void xsk_put_ctx (struct xsk_ctx *ctx,bool unmap) {struct xsk_umem *umem = ctx->umem;struct xdp_mmap_offsets off;int err; -if (--ctx->refcount ==0 ) { - err =xsk_get_mmap_offsets (umem->fd, &off); -if (!err) { -munmap (ctx->fill->ring - off.fr.desc, - off.fr.desc + umem->config.fill_size * -sizeof (__u64)); -munmap (ctx->comp->ring - off.cr.desc, - off.cr.desc + umem->config.comp_size * -sizeof (__u64)); - } +if (--ctx->refcount) +return ; -list_del (&ctx->list); -free (ctx); - } +if (!unmap) + goto out_free; + + err =xsk_get_mmap_offsets (umem->fd, &off); +if (err) + goto out_free; + + munmap(ctx->fill->ring - off.fr.desc, off.fr.desc + umem-config.fill_size *
tools/lib/bpf/xsk.c +2
-0+ sizeof(__u64)); + munmap(ctx->comp->ring - off.cr.desc, off.cr.desc + umem-config.comp_size *
tools/lib/bpf/xsk.c +5
-0+ sizeof(__u64)); + +out_free: +list_del (&ctx->list); +free (ctx); } static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,@@ -797,8 +801,6 @@ static struct xsk_ctx *xsk_create_ctx(struct
xsk_socket*xsk,tools/lib/bpf/xsk.c int xsk_socket__create_shared(struct xsk_socket
Quoted 9 lines
tools/lib/bpf/xsk.c +0
-2memcpy (ctx->ifname, ifname,IFNAMSIZ -1 ); ctx->ifname[IFNAMSIZ -1 ] ='\0' ; - umem->fill_save =NULL ; - umem->comp_save =NULL ; ctx->fill = fill; ctx->comp = comp;list_add (&ctx->list, &umem->ctx_list);@@ -854,6 +856,7 @@ int xsk_socket__create_shared(struct xsk_socket**xsk_ptr,
Quoted 8 lines
tools/lib/bpf/xsk.c int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, · line 860
Quoted 5 lines
tools/lib/bpf/xsk.c +1
-0struct xsk_socket *xsk;struct xsk_ctx *ctx;int err, ifindex; +bool unmap = umem->fill_save != fill;we are checking !umem only on the next line, so here it can be still NULL. Please send a fix, thanks.
Thank you for catching this. I've sent a fix.
Ciara
Quoted 35 lines
tools/lib/bpf/xsk.c int xsk_socket__create_shared(struct xsk_socket
Quoted 4 lines
tools/lib/bpf/xsk.c +0
-0if (!umem || !xsk_ptr || !(rx || tx))return -EFAULT ;@@ -994,6 +997,8 @@ int xsk_socket__create_shared(struct xsk_socket**xsk_ptr,
tools/lib/bpf/xsk.c int xsk_socket__create_shared(struct xsk_socket
Quoted 9 lines
tools/lib/bpf/xsk.c +2
-0} *xsk_ptr = xsk; + umem->fill_save =NULL ; + umem->comp_save =NULL ;return 0 ; out_mmap_tx:@@ -1005,7 +1010,7 @@ int xsk_socket__create_shared(struct xsk_socket**xsk_ptr,
Quoted 20 lines
tools/lib/bpf/xsk.c +2
-3munmap (rx_map, off.rx.desc + xsk->config.rx_size *sizeof (struct xdp_desc )); out_put_ctx: -xsk_put_ctx (ctx); +xsk_put_ctx (ctx, unmap); out_socket:if (--umem->refcount)close (xsk->fd);@@ -1071,7 +1076,7 @@ void xsk_socket__delete(struct xsk_socket *xsk) } } -xsk_put_ctx (ctx); +xsk_put_ctx (ctx, true); umem->refcount--;/* Do not close an fd that also has an associated umem connected -- 2.17.1
PATCH v4 3/3 libbpf: only create rx and tx XDP rings when necessary
In reply to Ciara LoftusPrior to this commit xsk_socket__create(_shared) always attempted to create the rx and tx rings for the socket. However this causes an issue when the socket being setup is that which shares the fd with the UMEM. If a previous call to this function failed with this socket after the rings were set up, a subsequent call would always fail because the rings are not torn down after the first call and when we try to set them up again we encounter an error because they already exist. Solve this by remembering whether the rings were set up by introducing new bools to struct xsk_umem which represent the ring setup status and using them to determine whether or not to set up the rings.
--- tools/lib/bpf/xsk.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
tools/lib/bpf/xsk.c +11 -2
@@ -59,6 +59,8 @@ struct xsk_umem {int fd;int refcount;struct list_head ctx_list; +bool rx_ring_setup_done; +bool tx_ring_setup_done; };struct xsk_ctx {
@@ -857,6 +859,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,struct xsk_ctx *ctx;int err, ifindex;bool unmap = umem->fill_save != fill; +bool rx_setup_done = false, tx_setup_done = false;if (!umem || !xsk_ptr || !(rx || tx))return -EFAULT ;
@@ -884,6 +887,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, } }else { xsk->fd = umem->fd; + rx_setup_done = umem->rx_ring_setup_done; + tx_setup_done = umem->tx_ring_setup_done; } ctx =xsk_get_ctx (umem, ifindex, queue_id);
@@ -902,7 +907,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, } xsk->ctx = ctx; -if (rx) { +if (rx && !rx_setup_done) { err =setsockopt (xsk->fd,SOL_XDP ,XDP_RX_RING , &xsk->config.rx_size,sizeof (xsk->config.rx_size));
@@ -910,8 +915,10 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, err = -errno; goto out_put_ctx; } +if (xsk->fd == umem->fd) + umem->rx_ring_setup_done = true; } -if (tx) { +if (tx && !tx_setup_done) { err =setsockopt (xsk->fd,SOL_XDP ,XDP_TX_RING , &xsk->config.tx_size,sizeof (xsk->config.tx_size));
@@ -919,6 +926,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, err = -errno; goto out_put_ctx; } +if (xsk->fd == umem->fd) + umem->rx_ring_setup_done = true; } err =xsk_get_mmap_offsets (xsk->fd, &off);
Signature · 1 line
2.17.1
Quoted 14 lines · Ciara Loftus
This series fixes some issues around socket creation for
AF_XDP.Patch 1 fixes a potential NULL pointer dereference in
xsk_socket__create_shared.Patch 2 ensures that the umem passed to
xsk_socket__create(_shared)remains unchanged in event of failure.Patch 3 makes it possible for
xsk_socket__create(_shared)to succeed even if the rx and tx XDP rings have already been set up by introducing a new fields to structxsk_umemwhich represent the ring setup status for the xsk which shares the fd with the umem.
Quoted 5 lines
v3->v4:
* Reduced nesting inxsk_put_ctxas suggested by Alexei.
* Use bools instead of a u8 and flags to represent the ring setup status as suggested by Björn.
Thanks, Ciara! LGTM!
Quoted 23 lines
v2->v3:
* Instead of ignoring the return values of the setsockopt calls, introduce a new flag to determine whether or not to call them based on the ring setup status as suggested by Alexei.
v1->v2:
* Simplified restoring the_savepointers as suggested by Magnus.
* Fixed the condition which determines whether to unmap umem rings when socket create fails.This series applies on commit
861de02e5f3f2a104eecc5af1d248cb7bf8c5f75Ciara Loftus (3):
libbpf: ensure umem pointer is non-NULL before dereferencing
libbpf: restore umem state after socket create failure
libbpf: only create rx and tx XDP rings when necessarytools/lib/bpf/xsk.c | 57 +++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 20 deletions(-)--
2.17.1
Alexei Starovoitov
AppliedQuoted 22 lines · Björn Töpel
Quoted 14 lines · Ciara Loftus
This series fixes some issues around socket creation for
AF_XDP.Patch 1 fixes a potential NULL pointer dereference in
xsk_socket__create_shared.Patch 2 ensures that the umem passed to
xsk_socket__create(_shared)remains unchanged in event of failure.Patch 3 makes it possible for
xsk_socket__create(_shared)to succeed even if the rx and tx XDP rings have already been set up by introducing a new fields to structxsk_umemwhich represent the ring setup status for the xsk which shares the fd with the umem.Quoted 5 lines
v3->v4:
* Reduced nesting inxsk_put_ctxas suggested by Alexei.
* Use bools instead of a u8 and flags to represent the ring setup status as suggested by Björn.
Quoted 3 lines
Thanks, Ciara! LGTM!
Acked-by Björn Töpel <[email protected]>
Applied. Thanks