The ice_ptp_request_ts() function is used to request a timestamp index for
use with a packet. When reserving an index, it sets the start time and
saves a pointer to the skb into the appropriate index. The function marks
the in_use bit first before doing any of these steps. The IRQ handler which
clears the timestamps reads the in_use bits uses a lockless flow for
reading the in_use bits to determine which ones are in-use. This is
necessary as actually processing a complete timestamp must be able to sleep
so we cannot hold the timestamp tracker lock over the entire sequence.
Additionally, blocking the Tx hotpath with such a lock indefinitely would
be problematic.

However, the existing flow now has a very narrow window where the IRQ
handler could see a timestamp as in-use but read a stale value for its
"start" time.

Fix this by ordering the sequence to mark the in_use bit last, and add a
memory barrier to prevent re-ordering of the previous writes to setup the
index.

This was found and reported by Sashiko while reviewing an unrelated change.

Closes: 
https://sashiko.dev/#/patchset/20260821-jk-e825c-minimized-fixes-v1-0-9d0731eb4858%40intel.com?part=7
Fixes: ea9b847cda64 ("ice: enable transmit timestamps for E810 devices")
Signed-off-by: Jacob Keller <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice_ptp.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c 
b/drivers/net/ethernet/intel/ice/ice_ptp.c
index adc5308baefc..bbb57edcec0f 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -592,6 +592,9 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
                bool drop_ts = !link_up;
                struct sk_buff *skb;
 
+               /* Prevent speculative re-ordering of start and skb */
+               smp_rmb();
+
                /* Drop packets which have waited for more than 2 seconds */
                if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
                        drop_ts = true;
@@ -2670,11 +2673,13 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct 
sk_buff *skb)
                 * a reference to the skb and the start time to allow 
discarding old
                 * requests.
                 */
-               set_bit(idx, tx->in_use);
-               clear_bit(idx, tx->stale);
                tx->tstamps[idx].start = jiffies;
                tx->tstamps[idx].skb = skb_get(skb);
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               clear_bit(idx, tx->stale);
+               /* Ensure index is setup before marking it as used */
+               smp_mb__before_atomic();
+               set_bit(idx, tx->in_use);
                ice_trace(tx_tstamp_request, skb, idx);
        }
 

-- 
2.56.0.rc0.395.gd1f3524e15dc

Reply via email to