[PATCH 6.18 128/175] ice: Fix PTP NULL pointer dereference during VSI rebuild

Greg Kroah-Hartman
2026-02-09T14:34:05Z

From: Aaron Ma <aaron.ma@canonical.com>

[ Upstream commit fc6f36eaaedcf4b81af6fe1a568f018ffd530660 ]

Fix race condition where PTP periodic work runs while VSI is being
rebuilt, accessing NULL vsi->rx_rings.

The sequence was:
1. ice_ptp_prepare_for_reset() cancels PTP work
2. ice_ptp_rebuild() immediately queues PTP work
3. VSI rebuild happens AFTER ice_ptp_rebuild()
4. PTP work runs and accesses NULL vsi->rx_rings

Fix: Keep PTP work cancelled during rebuild, only queue it after
VSI rebuild completes in ice_rebuild().

Added ice_ptp_queue_work() helper function to encapsulate the logic
for queuing PTP work, ensuring it's only queued when PTP is supported
and the state is ICE_PTP_READY.

Error log:
[ 121.392544] ice 0000:60:00.1: PTP reset successful
[ 121.392692] BUG: kernel NULL pointer dereference, address: 0000000000000000
[ 121.392712] #PF: supervisor read access in kernel mode
[ 121.392720] #PF: error_code(0x0000) - not-present page
[ 121.392727] PGD 0
[ 121.392734] Oops: Oops: 0000 [#1] SMP NOPTI
[ 121.392746] CPU: 8 UID: 0 PID: 1005 Comm: ice-ptp-0000:60 Tainted: G S 6.19.0-rc6+ #4 PREEMPT(voluntary)
[ 121.392761] Tainted: [S]=CPU_OUT_OF_SPEC
[ 121.392773] RIP: 0010:ice_ptp_update_cached_phctime+0xbf/0x150 [ice]
[ 121.393042] Call Trace:
[ 121.393047] <TASK>
[ 121.393055] ice_ptp_periodic_work+0x69/0x180 [ice]
[ 121.393202] kthread_worker_fn+0xa2/0x260
[ 121.393216] ? __pfx_ice_ptp_periodic_work+0x10/0x10 [ice]
[ 121.393359] ? __pfx_kthread_worker_fn+0x10/0x10
[ 121.393371] kthread+0x10d/0x230
[ 121.393382] ? __pfx_kthread+0x10/0x10
[ 121.393393] ret_from_fork+0x273/0x2b0
[ 121.393407] ? __pfx_kthread+0x10/0x10
[ 121.393417] ret_from_fork_asm+0x1a/0x30
[ 121.393432] </TASK>

Fixes: 803bef817807d ("ice: factor out ice_ptp_rebuild_owner()")
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
Tested-by: Sunitha Mekala <sunithax.d.mekala@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice_main.c | 3 +++
drivers/net/ethernet/intel/ice/ice_ptp.c | 26 ++++++++++++++++++-----
drivers/net/ethernet/intel/ice/ice_ptp.h | 5 +++++
3 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 7a59c9dd07cb1..d34a32a09bf87 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -7815,6 +7815,9 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)

/* Restore timestamp mode settings after VSI rebuild */
ice_ptp_restore_timestamp_mode(pf);
+
+ /* Start PTP periodic work after VSI is fully rebuilt */
+ ice_ptp_queue_work(pf);
return;

err_vsi_rebuild:
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 44c1ca58b8806..df38345b12d72 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -2832,6 +2832,20 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
msecs_to_jiffies(err ? 10 : 500));
}

+/**
+ * ice_ptp_queue_work - Queue PTP periodic work for a PF
+ * @pf: Board private structure
+ *
+ * Helper function to queue PTP periodic work after VSI rebuild completes.
+ * This ensures that PTP work only runs when VSI structures are ready.
+ */
+void ice_ptp_queue_work(struct ice_pf *pf)
+{
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags) &&
+ pf->ptp.state == ICE_PTP_READY)
+ kthread_queue_delayed_work(pf->ptp.kworker, &pf->ptp.work, 0);
+}
+
/**
* ice_ptp_prepare_rebuild_sec - Prepare second NAC for PTP reset or rebuild
* @pf: Board private structure
@@ -2850,10 +2864,15 @@ static void ice_ptp_prepare_rebuild_sec(struct ice_pf *pf, bool rebuild,
struct ice_pf *peer_pf = ptp_port_to_pf(port);

if (!ice_is_primary(&peer_pf->hw)) {
- if (rebuild)
+ if (rebuild) {
+ /* TODO: When implementing rebuild=true:
+ * 1. Ensure secondary PFs' VSIs are rebuilt
+ * 2. Call ice_ptp_queue_work(peer_pf) after VSI rebuild
+ */
ice_ptp_rebuild(peer_pf, reset_type);
- else
+ } else {
ice_ptp_prepare_for_reset(peer_pf, reset_type);
+ }
}
}
}
@@ -2999,9 +3018,6 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)

ptp->state = ICE_PTP_READY;

- /* Start periodic work going */
- kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0);
-
dev_info(ice_pf_to_dev(pf), "PTP reset successful\n");
return;

diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h
index 46005642ef419..4e02f922c1ff8 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.h
@@ -316,6 +316,7 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf,
void ice_ptp_init(struct ice_pf *pf);
void ice_ptp_release(struct ice_pf *pf);
void ice_ptp_link_change(struct ice_pf *pf, bool linkup);
+void ice_ptp_queue_work(struct ice_pf *pf);
#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */

static inline int ice_ptp_hwtstamp_get(struct net_device *netdev,
@@ -384,6 +385,10 @@ static inline void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
{
}

+static inline void ice_ptp_queue_work(struct ice_pf *pf)
+{
+}
+
static inline int ice_ptp_clock_index(struct ice_pf *pf)
{
return -1;
--
2.51.0