]> www.infradead.org Git - users/griffoul/linux.git/commitdiff
ice: fix NULL access of tx->in_use in ice_ptp_ts_irq
authorJacob Keller <jacob.e.keller@intel.com>
Thu, 7 Aug 2025 17:35:26 +0000 (10:35 -0700)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Tue, 2 Sep 2025 18:05:50 +0000 (11:05 -0700)
The E810 device has support for a "low latency" firmware interface to
access and read the Tx timestamps. This interface does not use the standard
Tx timestamp logic, due to the latency overhead of proxying sideband
command requests over the firmware AdminQ.

The logic still makes use of the Tx timestamp tracking structure,
ice_ptp_tx, as it uses the same "ready" bitmap to track which Tx
timestamps complete.

Unfortunately, the ice_ptp_ts_irq() function does not check if the tracker
is initialized before its first access. This results in NULL dereference or
use-after-free bugs similar to the following:

[245977.278756] BUG: kernel NULL pointer dereference, address: 0000000000000000
[245977.278774] RIP: 0010:_find_first_bit+0x19/0x40
[245977.278796] Call Trace:
[245977.278809]  ? ice_misc_intr+0x364/0x380 [ice]

This can occur if a Tx timestamp interrupt races with the driver reset
logic.

Fix this by only checking the in_use bitmap (and other fields) if the
tracker is marked as initialized. The reset flow will clear the init field
under lock before it tears the tracker down, thus preventing any
use-after-free or NULL access.

Fixes: f9472aaabd1f ("ice: Process TSYN IRQ in a separate function")
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_ptp.c

index e358eb1d719f754f2ee3655a900df4a692682760..fb0f6365a6d6f17c32dad0ee27111f068887ba24 100644 (file)
@@ -2701,16 +2701,19 @@ irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf)
                 */
                if (hw->dev_caps.ts_dev_info.ts_ll_int_read) {
                        struct ice_ptp_tx *tx = &pf->ptp.port.tx;
-                       u8 idx;
+                       u8 idx, last;
 
                        if (!ice_pf_state_is_nominal(pf))
                                return IRQ_HANDLED;
 
                        spin_lock(&tx->lock);
-                       idx = find_next_bit_wrap(tx->in_use, tx->len,
-                                                tx->last_ll_ts_idx_read + 1);
-                       if (idx != tx->len)
-                               ice_ptp_req_tx_single_tstamp(tx, idx);
+                       if (tx->init) {
+                               last = tx->last_ll_ts_idx_read + 1;
+                               idx = find_next_bit_wrap(tx->in_use, tx->len,
+                                                        last);
+                               if (idx != tx->len)
+                                       ice_ptp_req_tx_single_tstamp(tx, idx);
+                       }
                        spin_unlock(&tx->lock);
 
                        return IRQ_HANDLED;