Skip to content

Commit 37d0103

Browse files
tohojokuba-moo
authored andcommitted
net: atlantic: Fix crash when XDP is enabled but no program is loaded
The aq_xdp_run_prog() function falls back to the XDP_ABORTED action handler (using a goto) if the operations for any of the other actions fail. The XDP_ABORTED handler in turn calls the bpf_warn_invalid_xdp_action() tracepoint. However, the function also jumps into the XDP_PASS helper if no XDP program is loaded on the device, which means the XDP_ABORTED handler can be run with a NULL program pointer. This results in a NULL pointer deref because the tracepoint dereferences the 'prog' pointer passed to it. This situation can happen in multiple ways: - If a packet arrives between the removal of the program from the interface and the static_branch_dec() in aq_xdp_setup() - If there are multiple devices using the same driver in the system and one of them has an XDP program loaded and the other does not. Fix this by refactoring the aq_xdp_run_prog() function to remove the 'goto pass' handling if there is no XDP program loaded. Instead, factor out the skb building in a separate small helper function. Fixes: 26efaef ("net: atlantic: Implement xdp data plane") Reported-by: Freysteinn Alfredsson <[email protected]> Tested-by: Freysteinn Alfredsson <[email protected]> Signed-off-by: Toke Høiland-Jørgensen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 43ffe6c commit 37d0103

File tree

1 file changed

+21
-7
lines changed
  • drivers/net/ethernet/aquantia/atlantic

1 file changed

+21
-7
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_ring.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,25 @@ int aq_xdp_xmit(struct net_device *dev, int num_frames,
412412
return num_frames - drop;
413413
}
414414

415+
static struct sk_buff *aq_xdp_build_skb(struct xdp_buff *xdp,
416+
struct net_device *dev,
417+
struct aq_ring_buff_s *buff)
418+
{
419+
struct xdp_frame *xdpf;
420+
struct sk_buff *skb;
421+
422+
xdpf = xdp_convert_buff_to_frame(xdp);
423+
if (unlikely(!xdpf))
424+
return NULL;
425+
426+
skb = xdp_build_skb_from_frame(xdpf, dev);
427+
if (!skb)
428+
return NULL;
429+
430+
aq_get_rxpages_xdp(buff, xdp);
431+
return skb;
432+
}
433+
415434
static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
416435
struct xdp_buff *xdp,
417436
struct aq_ring_s *rx_ring,
@@ -431,7 +450,7 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
431450

432451
prog = READ_ONCE(rx_ring->xdp_prog);
433452
if (!prog)
434-
goto pass;
453+
return aq_xdp_build_skb(xdp, aq_nic->ndev, buff);
435454

436455
prefetchw(xdp->data_hard_start); /* xdp_frame write */
437456

@@ -442,17 +461,12 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
442461
act = bpf_prog_run_xdp(prog, xdp);
443462
switch (act) {
444463
case XDP_PASS:
445-
pass:
446-
xdpf = xdp_convert_buff_to_frame(xdp);
447-
if (unlikely(!xdpf))
448-
goto out_aborted;
449-
skb = xdp_build_skb_from_frame(xdpf, aq_nic->ndev);
464+
skb = aq_xdp_build_skb(xdp, aq_nic->ndev, buff);
450465
if (!skb)
451466
goto out_aborted;
452467
u64_stats_update_begin(&rx_ring->stats.rx.syncp);
453468
++rx_ring->stats.rx.xdp_pass;
454469
u64_stats_update_end(&rx_ring->stats.rx.syncp);
455-
aq_get_rxpages_xdp(buff, xdp);
456470
return skb;
457471
case XDP_TX:
458472
xdpf = xdp_convert_buff_to_frame(xdp);

0 commit comments

Comments
 (0)