netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] net: atlantic: Fix NULL dereference of skb pointer in
@ 2023-12-04  8:58 Daniil Maximov
  2023-12-04 16:06 ` [EXT] " Igor Russkikh
  2023-12-06 10:50 ` patchwork-bot+netdevbpf
  0 siblings, 2 replies; 4+ messages in thread
From: Daniil Maximov @ 2023-12-04  8:58 UTC (permalink / raw)
  To: Egor Pomozov
  Cc: Daniil Maximov, Igor Russkikh, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Richard Cochran, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Taehee Yoo, Alexey Khoroshilov, netdev, linux-kernel, bpf,
	lvc-project

If is_ptp_ring == true in the loop of __aq_ring_xdp_clean function,
then a timestamp is stored from a packet in a field of skb object,
which is not allocated at the moment of the call (skb == NULL).

Generalize aq_ptp_extract_ts and other affected functions so they don't
work with struct sk_buff*, but with struct skb_shared_hwtstamps*.

Found by Linux Verification Center (linuxtesting.org) with SVACE

Fixes: 26efaef759a1 ("net: atlantic: Implement xdp data plane")
Signed-off-by: Daniil Maximov <daniil31415it@gmail.com>
---
 .../net/ethernet/aquantia/atlantic/aq_ptp.c    | 10 +++++-----
 .../net/ethernet/aquantia/atlantic/aq_ptp.h    |  4 ++--
 .../net/ethernet/aquantia/atlantic/aq_ring.c   | 18 ++++++++++++------
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
index 80b44043e6c5..28c9b6f1a54f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -553,17 +553,17 @@ void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp)
 
 /* aq_ptp_rx_hwtstamp - utility function which checks for RX time stamp
  * @adapter: pointer to adapter struct
- * @skb: particular skb to send timestamp with
+ * @shhwtstamps: particular skb_shared_hwtstamps to save timestamp
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the hwtstamps structure which
  * is passed up the network stack
  */
-static void aq_ptp_rx_hwtstamp(struct aq_ptp_s *aq_ptp, struct sk_buff *skb,
+static void aq_ptp_rx_hwtstamp(struct aq_ptp_s *aq_ptp, struct skb_shared_hwtstamps *shhwtstamps,
 			       u64 timestamp)
 {
 	timestamp -= atomic_read(&aq_ptp->offset_ingress);
-	aq_ptp_convert_to_hwtstamp(aq_ptp, skb_hwtstamps(skb), timestamp);
+	aq_ptp_convert_to_hwtstamp(aq_ptp, shhwtstamps, timestamp);
 }
 
 void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp,
@@ -639,7 +639,7 @@ bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring)
 	       &aq_ptp->ptp_rx == ring || &aq_ptp->hwts_rx == ring;
 }
 
-u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p,
+u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct skb_shared_hwtstamps *shhwtstamps, u8 *p,
 		      unsigned int len)
 {
 	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
@@ -648,7 +648,7 @@ u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p,
 						   p, len, &timestamp);
 
 	if (ret > 0)
-		aq_ptp_rx_hwtstamp(aq_ptp, skb, timestamp);
+		aq_ptp_rx_hwtstamp(aq_ptp, shhwtstamps, timestamp);
 
 	return ret;
 }
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
index 28ccb7ca2df9..210b723f2207 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
@@ -67,7 +67,7 @@ int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp,
 /* Return either ring is belong to PTP or not*/
 bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring);
 
-u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p,
+u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct skb_shared_hwtstamps *shhwtstamps, u8 *p,
 		      unsigned int len);
 
 struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp);
@@ -143,7 +143,7 @@ static inline bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring)
 }
 
 static inline u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic,
-				    struct sk_buff *skb, u8 *p,
+				    struct skb_shared_hwtstamps *shhwtstamps, u8 *p,
 				    unsigned int len)
 {
 	return 0;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 4de22eed099a..694daeaf3e61 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -647,7 +647,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi,
 		}
 		if (is_ptp_ring)
 			buff->len -=
-				aq_ptp_extract_ts(self->aq_nic, skb,
+				aq_ptp_extract_ts(self->aq_nic, skb_hwtstamps(skb),
 						  aq_buf_vaddr(&buff->rxdata),
 						  buff->len);
 
@@ -742,6 +742,8 @@ static int __aq_ring_xdp_clean(struct aq_ring_s *rx_ring,
 		struct aq_ring_buff_s *buff = &rx_ring->buff_ring[rx_ring->sw_head];
 		bool is_ptp_ring = aq_ptp_ring(rx_ring->aq_nic, rx_ring);
 		struct aq_ring_buff_s *buff_ = NULL;
+		u16 ptp_hwtstamp_len = 0;
+		struct skb_shared_hwtstamps shhwtstamps;
 		struct sk_buff *skb = NULL;
 		unsigned int next_ = 0U;
 		struct xdp_buff xdp;
@@ -810,11 +812,12 @@ static int __aq_ring_xdp_clean(struct aq_ring_s *rx_ring,
 		hard_start = page_address(buff->rxdata.page) +
 			     buff->rxdata.pg_off - rx_ring->page_offset;
 
-		if (is_ptp_ring)
-			buff->len -=
-				aq_ptp_extract_ts(rx_ring->aq_nic, skb,
-						  aq_buf_vaddr(&buff->rxdata),
-						  buff->len);
+		if (is_ptp_ring) {
+			ptp_hwtstamp_len = aq_ptp_extract_ts(rx_ring->aq_nic, &shhwtstamps,
+							     aq_buf_vaddr(&buff->rxdata),
+							     buff->len);
+			buff->len -= ptp_hwtstamp_len;
+		}
 
 		xdp_init_buff(&xdp, frame_sz, &rx_ring->xdp_rxq);
 		xdp_prepare_buff(&xdp, hard_start, rx_ring->page_offset,
@@ -834,6 +837,9 @@ static int __aq_ring_xdp_clean(struct aq_ring_s *rx_ring,
 		if (IS_ERR(skb) || !skb)
 			continue;
 
+		if (ptp_hwtstamp_len > 0)
+			*skb_hwtstamps(skb) = shhwtstamps;
+
 		if (buff->is_vlan)
 			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
 					       buff->vlan_rx_tag);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [EXT] [PATCH] net: atlantic: Fix NULL dereference of skb pointer in
  2023-12-04  8:58 [PATCH] net: atlantic: Fix NULL dereference of skb pointer in Daniil Maximov
@ 2023-12-04 16:06 ` Igor Russkikh
  2023-12-06 10:15   ` Даниил Максимов
  2023-12-06 10:50 ` patchwork-bot+netdevbpf
  1 sibling, 1 reply; 4+ messages in thread
From: Igor Russkikh @ 2023-12-04 16:06 UTC (permalink / raw)
  To: Daniil Maximov
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Richard Cochran, Alexei Starovoitov, Daniel Borkmann,
	Jesper Dangaard Brouer, John Fastabend, Taehee Yoo,
	Alexey Khoroshilov, netdev, linux-kernel, bpf, lvc-project


Hi Daniil,

> If is_ptp_ring == true in the loop of __aq_ring_xdp_clean function,
> then a timestamp is stored from a packet in a field of skb object,
> which is not allocated at the moment of the call (skb == NULL).
> 
> Generalize aq_ptp_extract_ts and other affected functions so they don't
> work with struct sk_buff*, but with struct skb_shared_hwtstamps*.
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE

Thanks for finding this and working on this.

Have you reproduced it in wild, or this just comes out of static analysis?

I'm asking because looking into the flow you described - it looks like XDP
mode should immediately fail with null pointer access on any rx traffic.
But that was never reported.

I will try to debug and validate the fix, but this may take some time.

So for now 

Reviewed-by: Igor Russkikh <irusskikh@marvell.com>


Thanks
  Igor

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [EXT] [PATCH] net: atlantic: Fix NULL dereference of skb pointer in
  2023-12-04 16:06 ` [EXT] " Igor Russkikh
@ 2023-12-06 10:15   ` Даниил Максимов
  0 siblings, 0 replies; 4+ messages in thread
From: Даниил Максимов @ 2023-12-06 10:15 UTC (permalink / raw)
  To: Igor Russkikh
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Richard Cochran, Alexei Starovoitov, Daniel Borkmann,
	Jesper Dangaard Brouer, John Fastabend, Taehee Yoo,
	Alexey Khoroshilov, netdev, linux-kernel, bpf, lvc-project,
	Egor Pomozov

I am sorry for breaking the mailing list and sending my answer only to
Igor, I've never used emails that much. To make it clear, the answer
was: "Hi Igor! No, it hasn't been reproduced in reality because I
don't have any appropriate device."


пн, 4 дек. 2023 г. в 19:06, Igor Russkikh <irusskikh@marvell.com>:
>
>
> Hi Daniil,
>
> > If is_ptp_ring == true in the loop of __aq_ring_xdp_clean function,
> > then a timestamp is stored from a packet in a field of skb object,
> > which is not allocated at the moment of the call (skb == NULL).
> >
> > Generalize aq_ptp_extract_ts and other affected functions so they don't
> > work with struct sk_buff*, but with struct skb_shared_hwtstamps*.
> >
> > Found by Linux Verification Center (linuxtesting.org) with SVACE
>
> Thanks for finding this and working on this.
>
> Have you reproduced it in wild, or this just comes out of static analysis?
>
> I'm asking because looking into the flow you described - it looks like XDP
> mode should immediately fail with null pointer access on any rx traffic.
> But that was never reported.
>
> I will try to debug and validate the fix, but this may take some time.
>
> So for now
>
> Reviewed-by: Igor Russkikh <irusskikh@marvell.com>
>
>
> Thanks
>   Igor

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] net: atlantic: Fix NULL dereference of skb pointer in
  2023-12-04  8:58 [PATCH] net: atlantic: Fix NULL dereference of skb pointer in Daniil Maximov
  2023-12-04 16:06 ` [EXT] " Igor Russkikh
@ 2023-12-06 10:50 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 4+ messages in thread
From: patchwork-bot+netdevbpf @ 2023-12-06 10:50 UTC (permalink / raw)
  To: =?utf-8?b?0JTQsNC90LjQuNC7INCc0LDQutGB0LjQvNC+0LIgPGRhbmlpbDMxNDE1aXRAZ21h?=,
	=?utf-8?b?aWwuY29tPg==?=
  Cc: epomozov, irusskikh, davem, edumazet, kuba, pabeni,
	richardcochran, ast, daniel, hawk, john.fastabend, ap420073,
	khoroshilov, netdev, linux-kernel, bpf, lvc-project

Hello:

This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:

On Mon,  4 Dec 2023 11:58:10 +0300 you wrote:
> If is_ptp_ring == true in the loop of __aq_ring_xdp_clean function,
> then a timestamp is stored from a packet in a field of skb object,
> which is not allocated at the moment of the call (skb == NULL).
> 
> Generalize aq_ptp_extract_ts and other affected functions so they don't
> work with struct sk_buff*, but with struct skb_shared_hwtstamps*.
> 
> [...]

Here is the summary with links:
  - net: atlantic: Fix NULL dereference of skb pointer in
    https://git.kernel.org/netdev/net/c/cbe860be3609

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-12-06 10:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-04  8:58 [PATCH] net: atlantic: Fix NULL dereference of skb pointer in Daniil Maximov
2023-12-04 16:06 ` [EXT] " Igor Russkikh
2023-12-06 10:15   ` Даниил Максимов
2023-12-06 10:50 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).