[PATCH net] bareudp: Fix invalid read beyond skb's linear data

Subsystems: networking drivers, the rest

STALE1853d LANDED

Landed in mainline as 143a8526ab5f on 2021-08-09.

6 messages, 3 authors, 2021-08-10 · open the first message on its own page

[PATCH net] bareudp: Fix invalid read beyond skb's linear data

From: Guillaume Nault <hidden>
Date: 2021-08-06 15:52:16

Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.

Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <redacted>
---
 drivers/net/bareudp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index a7ee0af1af90..54e321a695ce 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -71,12 +71,18 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		family = AF_INET6;
 
 	if (bareudp->ethertype == htons(ETH_P_IP)) {
-		struct iphdr *iphdr;
+		__u8 ipversion;
 
-		iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN);
-		if (iphdr->version == 4) {
-			proto = bareudp->ethertype;
-		} else if (bareudp->multi_proto_mode && (iphdr->version == 6)) {
+		if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion,
+				  sizeof(ipversion))) {
+			bareudp->dev->stats.rx_dropped++;
+			goto drop;
+		}
+		ipversion >>= 4;
+
+		if (ipversion == 4) {
+			proto = htons(ETH_P_IP);
+		} else if (ipversion == 6 && bareudp->multi_proto_mode) {
 			proto = htons(ETH_P_IPV6);
 		} else {
 			bareudp->dev->stats.rx_dropped++;
-- 
2.21.3

Re: [PATCH net] bareudp: Fix invalid read beyond skb's linear data

From: Jakub Kicinski <kuba@kernel.org>
Date: 2021-08-06 23:22:38

On Fri, 6 Aug 2021 17:52:06 +0200 Guillaume Nault wrote:
quoted hunk
Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.

Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <redacted>
---
 drivers/net/bareudp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index a7ee0af1af90..54e321a695ce 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -71,12 +71,18 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		family = AF_INET6;
 
 	if (bareudp->ethertype == htons(ETH_P_IP)) {
-		struct iphdr *iphdr;
+		__u8 ipversion;
 
-		iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN);
-		if (iphdr->version == 4) {
-			proto = bareudp->ethertype;
-		} else if (bareudp->multi_proto_mode && (iphdr->version == 6)) {
+		if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion,
+				  sizeof(ipversion))) {
No preference just curious - could skb_header_pointer() be better suited?
+			bareudp->dev->stats.rx_dropped++;
+			goto drop;
+		}
+		ipversion >>= 4;
+
+		if (ipversion == 4) {
+			proto = htons(ETH_P_IP);
+		} else if (ipversion == 6 && bareudp->multi_proto_mode) {
 			proto = htons(ETH_P_IPV6);
 		} else {
 			bareudp->dev->stats.rx_dropped++;

Re: [PATCH net] bareudp: Fix invalid read beyond skb's linear data

From: Guillaume Nault <hidden>
Date: 2021-08-08 16:16:32

On Fri, Aug 06, 2021 at 04:22:34PM -0700, Jakub Kicinski wrote:
On Fri, 6 Aug 2021 17:52:06 +0200 Guillaume Nault wrote:
quoted
Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.

Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <redacted>
---
 drivers/net/bareudp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index a7ee0af1af90..54e321a695ce 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -71,12 +71,18 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		family = AF_INET6;
 
 	if (bareudp->ethertype == htons(ETH_P_IP)) {
-		struct iphdr *iphdr;
+		__u8 ipversion;
 
-		iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN);
-		if (iphdr->version == 4) {
-			proto = bareudp->ethertype;
-		} else if (bareudp->multi_proto_mode && (iphdr->version == 6)) {
+		if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion,
+				  sizeof(ipversion))) {
No preference just curious - could skb_header_pointer() be better suited?
I have no preference either. I just used skb_copy_bits() because it
didn't seem useful to get a pointer to the buffer (just to read one
byte of data).

But I don't mind reposting with skb_header_pointer() if anyone prefers
that solution.

Re: [PATCH net] bareudp: Fix invalid read beyond skb's linear data

From: Jakub Kicinski <kuba@kernel.org>
Date: 2021-08-09 16:20:54

On Sun, 8 Aug 2021 18:16:25 +0200 Guillaume Nault wrote:
On Fri, Aug 06, 2021 at 04:22:34PM -0700, Jakub Kicinski wrote:
quoted
On Fri, 6 Aug 2021 17:52:06 +0200 Guillaume Nault wrote:  
quoted
Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.

Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <redacted>
---
 drivers/net/bareudp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index a7ee0af1af90..54e321a695ce 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -71,12 +71,18 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		family = AF_INET6;
 
 	if (bareudp->ethertype == htons(ETH_P_IP)) {
-		struct iphdr *iphdr;
+		__u8 ipversion;
 
-		iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN);
-		if (iphdr->version == 4) {
-			proto = bareudp->ethertype;
-		} else if (bareudp->multi_proto_mode && (iphdr->version == 6)) {
+		if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion,
+				  sizeof(ipversion))) {  
No preference just curious - could skb_header_pointer() be better suited?  
I have no preference either. I just used skb_copy_bits() because it
didn't seem useful to get a pointer to the buffer (just to read one
byte of data).
Right, the advantage would be in the "fast" case of skb_header_pointer()
being inlined.
But I don't mind reposting with skb_header_pointer() if anyone prefers
that solution.

Re: [PATCH net] bareudp: Fix invalid read beyond skb's linear data

From: patchwork-bot+netdevbpf@kernel.org
Date: 2021-08-09 22:40:11

Hello:

This patch was applied to netdev/net.git (refs/heads/master):

On Fri, 6 Aug 2021 17:52:06 +0200 you wrote:
Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.

Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <redacted>

[...]
Here is the summary with links:
  - [net] bareudp: Fix invalid read beyond skb's linear data
    https://git.kernel.org/netdev/net/c/143a8526ab5f

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

Re: [PATCH net] bareudp: Fix invalid read beyond skb's linear data

From: Guillaume Nault <hidden>
Date: 2021-08-10 09:33:24

On Mon, Aug 09, 2021 at 09:19:18AM -0700, Jakub Kicinski wrote:
On Sun, 8 Aug 2021 18:16:25 +0200 Guillaume Nault wrote:
quoted
On Fri, Aug 06, 2021 at 04:22:34PM -0700, Jakub Kicinski wrote:
quoted
On Fri, 6 Aug 2021 17:52:06 +0200 Guillaume Nault wrote:  
quoted
Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.

Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <redacted>
---
 drivers/net/bareudp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index a7ee0af1af90..54e321a695ce 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -71,12 +71,18 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		family = AF_INET6;
 
 	if (bareudp->ethertype == htons(ETH_P_IP)) {
-		struct iphdr *iphdr;
+		__u8 ipversion;
 
-		iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN);
-		if (iphdr->version == 4) {
-			proto = bareudp->ethertype;
-		} else if (bareudp->multi_proto_mode && (iphdr->version == 6)) {
+		if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion,
+				  sizeof(ipversion))) {  
No preference just curious - could skb_header_pointer() be better suited?  
I have no preference either. I just used skb_copy_bits() because it
didn't seem useful to get a pointer to the buffer (just to read one
byte of data).
Right, the advantage would be in the "fast" case of skb_header_pointer()
being inlined.
Yes indeed. The problem was found because of some automated functionnal
tests, not because of any practical use cases. So I didn't consider the
possible performance differences.

I see that you've applied the patch as is already. I can switch to
skb_header_pointer() in the future, if anyone sees any practical
benefit for it.

Thanks for the review.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help