diff mbox series

[net] ip_gre: validate csum_start only on pull

Message ID 20210905152109.1805619-1-willemdebruijn.kernel@gmail.com (mailing list archive)
State Accepted
Commit 8a0ed250f911da31a2aef52101bc707846a800ff
Delegated to: Netdev Maintainers
Headers show
Series [net] ip_gre: validate csum_start only on pull | expand

Checks

Context Check Description
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for net
netdev/subject_prefix success Link
netdev/cc_maintainers warning 2 maintainers not CCed: yoshfuji@linux-ipv6.org dsahern@kernel.org
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 29 lines checked
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success Link

Commit Message

Willem de Bruijn Sept. 5, 2021, 3:21 p.m. UTC
From: Willem de Bruijn <willemb@google.com>

The GRE tunnel device can pull existing outer headers in ipge_xmit.
This is a rare path, apparently unique to this device. The below
commit ensured that pulling does not move skb->data beyond csum_start.

But it has a false positive if ip_summed is not CHECKSUM_PARTIAL and
thus csum_start is irrelevant.

Refine to exclude this. At the same time simplify and strengthen the
test.

Simplify, by moving the check next to the offending pull, making it
more self documenting and removing an unnecessary branch from other
code paths.

Strengthen, by also ensuring that the transport header is correct and
therefore the inner headers will be after skb_reset_inner_headers.
The transport header is set to csum_start in skb_partial_csum_set.

Link: https://lore.kernel.org/netdev/YS+h%2FtqCJJiQei+W@shredder/
Fixes: 1d011c4803c7 ("ip_gre: add validation for csum_start")
Reported-by: Ido Schimmel <idosch@idosch.org>
Suggested-by: Alexander Duyck <alexander.duyck@gmail.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 net/ipv4/ip_gre.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

Comments

Alexander H Duyck Sept. 5, 2021, 3:47 p.m. UTC | #1
On Sun, Sep 5, 2021 at 8:21 AM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> From: Willem de Bruijn <willemb@google.com>
>
> The GRE tunnel device can pull existing outer headers in ipge_xmit.
> This is a rare path, apparently unique to this device. The below
> commit ensured that pulling does not move skb->data beyond csum_start.
>
> But it has a false positive if ip_summed is not CHECKSUM_PARTIAL and
> thus csum_start is irrelevant.
>
> Refine to exclude this. At the same time simplify and strengthen the
> test.
>
> Simplify, by moving the check next to the offending pull, making it
> more self documenting and removing an unnecessary branch from other
> code paths.
>
> Strengthen, by also ensuring that the transport header is correct and
> therefore the inner headers will be after skb_reset_inner_headers.
> The transport header is set to csum_start in skb_partial_csum_set.
>
> Link: https://lore.kernel.org/netdev/YS+h%2FtqCJJiQei+W@shredder/
> Fixes: 1d011c4803c7 ("ip_gre: add validation for csum_start")
> Reported-by: Ido Schimmel <idosch@idosch.org>
> Suggested-by: Alexander Duyck <alexander.duyck@gmail.com>
> Signed-off-by: Willem de Bruijn <willemb@google.com>
> ---
>  net/ipv4/ip_gre.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
> index 177d26d8fb9c..0fe6c936dc54 100644
> --- a/net/ipv4/ip_gre.c
> +++ b/net/ipv4/ip_gre.c
> @@ -473,8 +473,6 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
>
>  static int gre_handle_offloads(struct sk_buff *skb, bool csum)
>  {
> -       if (csum && skb_checksum_start(skb) < skb->data)
> -               return -EINVAL;
>         return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
>  }
>
> @@ -632,15 +630,20 @@ static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
>         }
>
>         if (dev->header_ops) {
> +               const int pull_len = tunnel->hlen + sizeof(struct iphdr);
> +
>                 if (skb_cow_head(skb, 0))
>                         goto free_skb;
>
>                 tnl_params = (const struct iphdr *)skb->data;
>
> +               if (pull_len > skb_transport_offset(skb))
> +                       goto free_skb;
> +
>                 /* Pull skb since ip_tunnel_xmit() needs skb->data pointing
>                  * to gre header.
>                  */
> -               skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
> +               skb_pull(skb, pull_len);
>                 skb_reset_mac_header(skb);
>         } else {
>                 if (skb_cow_head(skb, dev->needed_headroom))
> --
> 2.33.0.153.gba50c8fa24-goog
>

Looks good to me.

Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Ido Schimmel Sept. 5, 2021, 4:13 p.m. UTC | #2
On Sun, Sep 05, 2021 at 08:47:16AM -0700, Alexander Duyck wrote:
> Looks good to me.
> 
> Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>

Thanks Willem and Alex! Applied the patch to my tree. Will let you know
tomorrow morning after regression is complete (though I'm sure it's
fine).
patchwork-bot+netdevbpf@kernel.org Sept. 5, 2021, 6 p.m. UTC | #3
Hello:

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

On Sun,  5 Sep 2021 11:21:09 -0400 you wrote:
> From: Willem de Bruijn <willemb@google.com>
> 
> The GRE tunnel device can pull existing outer headers in ipge_xmit.
> This is a rare path, apparently unique to this device. The below
> commit ensured that pulling does not move skb->data beyond csum_start.
> 
> But it has a false positive if ip_summed is not CHECKSUM_PARTIAL and
> thus csum_start is irrelevant.
> 
> [...]

Here is the summary with links:
  - [net] ip_gre: validate csum_start only on pull
    https://git.kernel.org/netdev/net/c/8a0ed250f911

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
Ido Schimmel Sept. 6, 2021, 7:35 a.m. UTC | #4
On Sun, Sep 05, 2021 at 11:21:09AM -0400, Willem de Bruijn wrote:
> From: Willem de Bruijn <willemb@google.com>
> 
> The GRE tunnel device can pull existing outer headers in ipge_xmit.
> This is a rare path, apparently unique to this device. The below
> commit ensured that pulling does not move skb->data beyond csum_start.
> 
> But it has a false positive if ip_summed is not CHECKSUM_PARTIAL and
> thus csum_start is irrelevant.
> 
> Refine to exclude this. At the same time simplify and strengthen the
> test.
> 
> Simplify, by moving the check next to the offending pull, making it
> more self documenting and removing an unnecessary branch from other
> code paths.
> 
> Strengthen, by also ensuring that the transport header is correct and
> therefore the inner headers will be after skb_reset_inner_headers.
> The transport header is set to csum_start in skb_partial_csum_set.
> 
> Link: https://lore.kernel.org/netdev/YS+h%2FtqCJJiQei+W@shredder/
> Fixes: 1d011c4803c7 ("ip_gre: add validation for csum_start")
> Reported-by: Ido Schimmel <idosch@idosch.org>
> Suggested-by: Alexander Duyck <alexander.duyck@gmail.com>
> Signed-off-by: Willem de Bruijn <willemb@google.com>

FTR:

Tested-by: Ido Schimmel <idosch@nvidia.com>

Thanks
diff mbox series

Patch

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 177d26d8fb9c..0fe6c936dc54 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -473,8 +473,6 @@  static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
 
 static int gre_handle_offloads(struct sk_buff *skb, bool csum)
 {
-	if (csum && skb_checksum_start(skb) < skb->data)
-		return -EINVAL;
 	return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
 }
 
@@ -632,15 +630,20 @@  static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
 	}
 
 	if (dev->header_ops) {
+		const int pull_len = tunnel->hlen + sizeof(struct iphdr);
+
 		if (skb_cow_head(skb, 0))
 			goto free_skb;
 
 		tnl_params = (const struct iphdr *)skb->data;
 
+		if (pull_len > skb_transport_offset(skb))
+			goto free_skb;
+
 		/* Pull skb since ip_tunnel_xmit() needs skb->data pointing
 		 * to gre header.
 		 */
-		skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
+		skb_pull(skb, pull_len);
 		skb_reset_mac_header(skb);
 	} else {
 		if (skb_cow_head(skb, dev->needed_headroom))