NULL pointer dereference is reported in cases where idpf_vport_open()
fails during soft reset:

./xdpsock -i <inf> -q -r -N

[ 3179.186687] idpf 0000:83:00.0: Failed to initialize queue ids for vport 0: 
-12
[ 3179.276739] BUG: kernel NULL pointer dereference, address: 0000000000000010
[ 3179.277636] #PF: supervisor read access in kernel mode
[ 3179.278470] #PF: error_code(0x0000) - not-present page
[ 3179.279285] PGD 0
[ 3179.280083] Oops: Oops: 0000 [#1] SMP NOPTI
...
[ 3179.283997] Workqueue: events xp_release_deferred
[ 3179.284770] RIP: 0010:idpf_find_rxq_vec+0x17/0x30 [idpf]
...
[ 3179.291937] Call Trace:
[ 3179.292392]  <TASK>
[ 3179.292843]  idpf_qp_switch+0x25/0x820 [idpf]
[ 3179.293325]  idpf_xsk_pool_setup+0x7c/0x520 [idpf]
[ 3179.293803]  idpf_xdp+0x59/0x240 [idpf]
[ 3179.294275]  xp_disable_drv_zc+0x62/0xb0
[ 3179.294743]  xp_clear_dev+0x40/0xb0
[ 3179.295198]  xp_release_deferred+0x1f/0xa0
[ 3179.295648]  process_one_work+0x226/0x730
[ 3179.296106]  worker_thread+0x19e/0x340
[ 3179.296557]  ? __pfx_worker_thread+0x10/0x10
[ 3179.297009]  kthread+0xf4/0x130
[ 3179.297459]  ? __pfx_kthread+0x10/0x10
[ 3179.297910]  ret_from_fork+0x32c/0x410
[ 3179.298361]  ? __pfx_kthread+0x10/0x10
[ 3179.298702]  ret_from_fork_asm+0x1a/0x30

Fix the error handling of the soft reset in idpf_xdp_setup_prog() by
restoring the vport->xdp_prog to the old value. This avoids referencing
the orphaned prog that was copied to vport->xdp_prog in the soft reset
and prevents subsequent false positive by idpf_xdp_enabled().

Update the restart check in idpf_xsk_pool_setup() to use IDPF_VPORT_UP bit
instead of netif_running(). The idpf_vport_stop/start() calls will not
update the __LINK_STATE_START bit, making this test a false positive
should the soft reset fail.

Fixes: 3d57b2c00f09 ("idpf: add XSk pool initialization")
Signed-off-by: Emil Tantilov <[email protected]>
Reviewed-by: Aleksandr Loktionov <[email protected]>
---
 drivers/net/ethernet/intel/idpf/xdp.c | 7 ++++++-
 drivers/net/ethernet/intel/idpf/xsk.c | 4 +++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/xdp.c 
b/drivers/net/ethernet/intel/idpf/xdp.c
index cbccd4546768..b670f0ea20b3 100644
--- a/drivers/net/ethernet/intel/idpf/xdp.c
+++ b/drivers/net/ethernet/intel/idpf/xdp.c
@@ -488,12 +488,17 @@ static int idpf_xdp_setup_prog(struct idpf_vport *vport,
                                   "Could not reopen the vport after XDP 
setup");
 
                cfg->user_config.xdp_prog = old;
-               old = prog;
+               vport->xdp_prog = old;
+               if (prog)
+                       bpf_prog_put(prog);
+
+               goto out;
        }
 
        if (old)
                bpf_prog_put(old);
 
+out:
        libeth_xdp_set_redirect(vport->netdev, vport->xdp_prog);
 
        return ret;
diff --git a/drivers/net/ethernet/intel/idpf/xsk.c 
b/drivers/net/ethernet/intel/idpf/xsk.c
index d95d3efdfd36..b601b6c298c7 100644
--- a/drivers/net/ethernet/intel/idpf/xsk.c
+++ b/drivers/net/ethernet/intel/idpf/xsk.c
@@ -553,6 +553,7 @@ int idpf_xskrq_poll(struct idpf_rx_queue *rxq, u32 budget)
 
 int idpf_xsk_pool_setup(struct idpf_vport *vport, struct netdev_bpf *bpf)
 {
+       const struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
        struct xsk_buff_pool *pool = bpf->xsk.pool;
        u32 qid = bpf->xsk.queue_id;
        bool restart;
@@ -568,7 +569,8 @@ int idpf_xsk_pool_setup(struct idpf_vport *vport, struct 
netdev_bpf *bpf)
                return -EINVAL;
        }
 
-       restart = idpf_xdp_enabled(vport) && netif_running(vport->netdev);
+       restart = idpf_xdp_enabled(vport) &&
+              test_bit(IDPF_VPORT_UP, np->state);
        if (!restart)
                goto pool;
 
-- 
2.37.3

Reply via email to