Re: [PATCH net-next 7/7] net: dsa: netc: add PTP one-step timestamping support
[email protected] Wed, 29 Jul 2026 10:43:16 +0000
| Newsgroups | dev.linux.lists.imx |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] The in-flight one-step Sync SKB outlives the DSA port structures on driver unbind, causing a Use-After-Free in the SKB destructor. - [High] The unbounded skb_onestep_queue can cause an Out-Of-Memory (OOM) crash if an attacker floods the port with forwarded PTP Sync packets. - [High] Calling ptp_parse_header() without ensuring the packet headers are in the linear data area causes an out-of-bounds read on fragmented packets. - [Medium] Modifying the PTP originTimestamp in software without updating the UDP checksum breaks the checksum for non-offloaded packets. -- --- Patch [7]: [PATCH net-next 7/7] net: dsa: netc: add PTP one-step timestamping support --- commit df83cf11f57c79cb36a98872a09e3e01dbf7936a Author: Wei Fang <[email protected]> net: dsa: netc: add PTP one-step timestamping support This commit adds one-step TX timestamping support for PTP Sync frames on the NETC switch. It implements serialization of one-step Sync transmission per port and intercepts packets to program the PTP originTimestamp before handing the frame to the hardware. > diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c > --- a/drivers/net/dsa/netc/netc_main.c > +++ b/drivers/net/dsa/netc/netc_main.c [ ... ] > @@ -1011,6 +1014,8 @@ static void netc_free_ports_resources(struct netc_switch *priv) > * (sock_efree) while holding a spinlock. > */ > __skb_queue_purge(&np->skb_txtstamp_queue); > + cancel_work_sync(&np->onestep_work); > + __skb_queue_purge(&np->skb_onestep_queue); [Severity: High] Does this teardown path need to wait for or cancel in-flight packets that were already handed off to the conduit device? Local queues are purged, but an SKB currently in-flight might retain a pointer to the port structure in its destructor. > } > } > diff --git a/drivers/net/dsa/netc/netc_ptp.c b/drivers/net/dsa/netc/netc_ptp.c > --- a/drivers/net/dsa/netc/netc_ptp.c > +++ b/drivers/net/dsa/netc/netc_ptp.c [ ... ] > +static void netc_port_prepare_onestep_sync(struct netc_port *np, > + struct sk_buff *skb, > + u32 ptp_class, bool *twostep) > +{ > + struct netc_switch *priv = np->switch_priv; > + u16 correction_offset, timestamp_offset; > + struct ptp_header *ptp_hdr; > + u8 msg_type, twostep_flag; > + bool is_udp = false; > + u32 pkt_type; > + u8 *pkt_hdr; > + > + ptp_hdr = ptp_parse_header(skb, ptp_class); > + if (!ptp_hdr) { [Severity: High] Does calling ptp_parse_header() here risk an out-of-bounds read if the packet is fragmented? The function directly accesses the IP header, but the code hasn't verified that the headers are in the linear data area using pskb_may_pull() yet. The bounds check later in this function happens after the read has already occurred. > + dev_dbg_ratelimited(priv->dev, > + "Port %d failed to parse Sync header\n", > + np->dp->index); > + return; > + } [ ... ] > +static void netc_port_program_onestep(struct netc_port *np, > + struct sk_buff *skb, > + u64 tstamp) > +{ > + u16 correction_offset = NETC_SKB_CB(skb)->correction_offset; > + u16 timestamp_offset = NETC_SKB_CB(skb)->timestamp_offset; > + bool is_udp = NETC_SKB_CB(skb)->is_udp; > + u8 *pkt_hdr = skb_mac_header(skb); > + u64 sec; > + u32 ns; > + > + NETC_SKB_CB(skb)->tstamp = tstamp; > + NETC_SKB_CB(skb)->ptp_flag = NETC_PTP_FLAG_ONESTEP; > + > + /* Update originTimestamp field of Sync packet > + * - 48 bits seconds field > + * - 32 bits nanoseconds field > + */ > + sec = div_u64_rem(tstamp, NSEC_PER_SEC, &ns); > + put_unaligned_be16((sec >> 32) & 0xffff, pkt_hdr + timestamp_offset); > + put_unaligned_be32(sec & 0xffffffff, pkt_hdr + timestamp_offset + 2); > + put_unaligned_be32(ns, pkt_hdr + timestamp_offset + 6); [Severity: Medium] Does modifying the originTimestamp payload here break the UDP checksum for non-offloaded packets? The hardware PM_SINGLE_STEP_CH feature only updates the checksum for the residence time delta it adds to the correction field. Do we need to incrementally update the software checksum for this payload modification? > + > + netc_port_set_onestep_control(np, is_udp, correction_offset); > + > + /* Orphan the skb to release the socket send buffer quota immediately. > + * This is safe because sock_wfree() only updates sk_wmem_alloc and > + * does not touch skb->data. After skb_orphan(), we install our own > + * destructor so that when the conduit driver frees the skb after TX > + * completion, we get notified to send the next queued Sync packet. > + */ > + skb_orphan(skb); > + skb_shinfo(skb)->destructor_arg = np; > + skb->destructor = netc_onestep_skb_destructor; [Severity: High] Can this in-flight SKB outlive the netc_port structure during driver unbind? If the driver unbinds while this packet is still queued in the conduit device, the devres-managed netc_port will be freed. When the conduit device later transmits and frees the SKB, will netc_onestep_skb_destructor() dereference a freed pointer? > +} [ ... ] > +struct sk_buff *netc_onestep_sync_handler(struct dsa_switch *ds, int port, > + struct sk_buff *skb) > +{ > + struct netc_port *np = NETC_PORT(ds, port); > + struct netc_switch *priv = ds->priv; > + u64 tstamp; > + > + /* Serialize one-step Sync packets: only one can be in-flight at a > + * time because the SINGLE_STEP register is shared and must match the > + * packet currently being transmitted. Claim the in-flight slot under > + * ptp_lock. If another one-step Sync is already in-flight, queue this > + * skb and return NULL; ownership is transferred to the queue, so no > + * extra reference is needed and netc_xmit() stops processing it. > + */ > + spin_lock_bh(&np->ptp_lock); > + if (test_bit(NETC_FLAG_ONESTEP_IN_PROGRESS, &np->flags)) { > + __skb_queue_tail(&np->skb_onestep_queue, skb); > + spin_unlock_bh(&np->ptp_lock); > + > + return NULL; [Severity: High] Is there a risk of memory exhaustion if an external source floods the port with forwarded PTP Sync packets? Since this queue has no length limit and returning NULL consumes the SKB, dsa_user_xmit() will return NETDEV_TX_OK, bypassing qdisc backpressure mechanisms. > + } > + > + tstamp = netc_timer_get_current_time(priv->tmr_dev); -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=7