netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net v3] xen-netback: fix fragment detection in checksum setup
@ 2013-11-29 10:52 Paul Durrant
  2013-11-30 21:13 ` David Miller
  0 siblings, 1 reply; 4+ messages in thread
From: Paul Durrant @ 2013-11-29 10:52 UTC (permalink / raw)
  To: xen-devel, netdev; +Cc: Paul Durrant, Wei Liu, Ian Campbell, David Vrabel

The code to detect fragments in checksum_setup() was missing for IPv4 and
too eager for IPv6. (It transpires that Windows seems to send IPv6 packets
with a fragment header even if they are not a fragment - i.e. offset is zero,
and M bit is not set).

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Cc: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: David Vrabel <david.vrabel@citrix.com>
---
v3
- Use defined values for 'fragment offset' and 'more fragments'

v2
- Added comments noting what fragment/offset masks mean


 drivers/net/xen-netback/netback.c |   31 ++++++++++++++++++++++++++++---
 include/net/ipv6.h                |    3 ++-
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 64f0e0d..53419f6 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1166,15 +1166,27 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
 	struct iphdr *iph = (void *)skb->data;
 	unsigned int header_size;
 	unsigned int off;
+	bool fragment;
 	int err = -EPROTO;
 
+	fragment = false;
+
 	off = sizeof(struct iphdr);
 
 	header_size = skb->network_header + off + MAX_IPOPTLEN;
 	maybe_pull_tail(skb, header_size);
 
+	if (iph->frag_off & htons(IP_OFFSET | IP_MF))
+		fragment = true;
+
 	off = iph->ihl * 4;
 
+	if (fragment) {
+		if (net_ratelimit())
+			netdev_err(vif->dev, "Packet is a fragment!\n");
+		goto out;
+	}
+
 	switch (iph->protocol) {
 	case IPPROTO_TCP:
 		if (!skb_partial_csum_set(skb, off,
@@ -1238,6 +1250,7 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
 	bool fragment;
 	bool done;
 
+	fragment = false;
 	done = false;
 
 	off = sizeof(struct ipv6hdr);
@@ -1276,9 +1289,21 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
 			off += (hp->hdrlen+2)<<2;
 			break;
 		}
-		case IPPROTO_FRAGMENT:
-			fragment = true;
-			/* fall through */
+		case IPPROTO_FRAGMENT: {
+			struct frag_hdr *hp = (void *)(skb->data + off);
+
+			header_size = skb->network_header +
+				off +
+				sizeof(struct frag_hdr);
+			maybe_pull_tail(skb, header_size);
+
+			if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
+				fragment = true;
+
+			nexthdr = hp->nexthdr;
+			off += sizeof(struct frag_hdr);
+			break;
+		}
 		default:
 			done = true;
 			break;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index eb198ac..488316e 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -110,7 +110,8 @@ struct frag_hdr {
 	__be32	identification;
 };
 
-#define	IP6_MF	0x0001
+#define	IP6_MF		0x0001
+#define	IP6_OFFSET	0xFFF8
 
 #include <net/sock.h>
 
-- 
1.7.10.4

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

* Re: [PATCH net v3] xen-netback: fix fragment detection in checksum setup
  2013-11-29 10:52 [PATCH net v3] xen-netback: fix fragment detection in checksum setup Paul Durrant
@ 2013-11-30 21:13 ` David Miller
  2013-12-02  9:45   ` Paul Durrant
  0 siblings, 1 reply; 4+ messages in thread
From: David Miller @ 2013-11-30 21:13 UTC (permalink / raw)
  To: paul.durrant; +Cc: xen-devel, netdev, wei.liu2, ian.campbell, david.vrabel

From: Paul Durrant <paul.durrant@citrix.com>
Date: Fri, 29 Nov 2013 10:52:08 +0000

> @@ -1166,15 +1166,27 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
>  	struct iphdr *iph = (void *)skb->data;
>  	unsigned int header_size;
>  	unsigned int off;
> +	bool fragment;
>  	int err = -EPROTO;
>  
> +	fragment = false;
> +
>  	off = sizeof(struct iphdr);
>  
>  	header_size = skb->network_header + off + MAX_IPOPTLEN;
>  	maybe_pull_tail(skb, header_size);
>  
> +	if (iph->frag_off & htons(IP_OFFSET | IP_MF))
> +		fragment = true;

This function has a serious problem.

maybe_pull_tail() can change skb->data, therefore this "iph" pointer
can become invalid, you're essentially dereferencing garbage if
maybe_pull_tail() actually does any work.

Secondly, do you really (even rate limited) want to span the system
log just because some ipv4 fragmented frames end up here?  That
doesn't make any sense to me.  Maybe bump a statistic or something
like that, but a log message triggerable by a remote entity?  No way.

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

* RE: [PATCH net v3] xen-netback: fix fragment detection in checksum setup
  2013-11-30 21:13 ` David Miller
@ 2013-12-02  9:45   ` Paul Durrant
  2013-12-02 17:27     ` Ben Hutchings
  0 siblings, 1 reply; 4+ messages in thread
From: Paul Durrant @ 2013-12-02  9:45 UTC (permalink / raw)
  To: David Miller
  Cc: xen-devel@lists.xen.org, netdev@vger.kernel.org, Wei Liu,
	Ian Campbell, David Vrabel

> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net]
> Sent: 30 November 2013 21:14
> To: Paul Durrant
> Cc: xen-devel@lists.xen.org; netdev@vger.kernel.org; Wei Liu; Ian Campbell;
> David Vrabel
> Subject: Re: [PATCH net v3] xen-netback: fix fragment detection in checksum
> setup
> 
> From: Paul Durrant <paul.durrant@citrix.com>
> Date: Fri, 29 Nov 2013 10:52:08 +0000
> 
> > @@ -1166,15 +1166,27 @@ static int checksum_setup_ip(struct xenvif *vif,
> struct sk_buff *skb,
> >  	struct iphdr *iph = (void *)skb->data;
> >  	unsigned int header_size;
> >  	unsigned int off;
> > +	bool fragment;
> >  	int err = -EPROTO;
> >
> > +	fragment = false;
> > +
> >  	off = sizeof(struct iphdr);
> >
> >  	header_size = skb->network_header + off + MAX_IPOPTLEN;
> >  	maybe_pull_tail(skb, header_size);
> >
> > +	if (iph->frag_off & htons(IP_OFFSET | IP_MF))
> > +		fragment = true;
> 
> This function has a serious problem.
> 
> maybe_pull_tail() can change skb->data, therefore this "iph" pointer
> can become invalid, you're essentially dereferencing garbage if
> maybe_pull_tail() actually does any work.

Ok. Clearly I'm misunderstanding what __pskb_pull_tail() does then. I was under the impression that it moved skb->tail on but left skb->data alone (which is what I want to do). I will have another look.

> 
> Secondly, do you really (even rate limited) want to span the system
> log just because some ipv4 fragmented frames end up here?  That
> doesn't make any sense to me.  Maybe bump a statistic or something
> like that, but a log message triggerable by a remote entity?  No way.

Ok.

  Paul

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

* Re: [PATCH net v3] xen-netback: fix fragment detection in checksum setup
  2013-12-02  9:45   ` Paul Durrant
@ 2013-12-02 17:27     ` Ben Hutchings
  0 siblings, 0 replies; 4+ messages in thread
From: Ben Hutchings @ 2013-12-02 17:27 UTC (permalink / raw)
  To: Paul Durrant
  Cc: David Miller, xen-devel@lists.xen.org, netdev@vger.kernel.org,
	Wei Liu, Ian Campbell, David Vrabel

On Mon, 2013-12-02 at 09:45 +0000, Paul Durrant wrote:
> > -----Original Message-----
> > From: David Miller [mailto:davem@davemloft.net]
> > Sent: 30 November 2013 21:14
> > To: Paul Durrant
> > Cc: xen-devel@lists.xen.org; netdev@vger.kernel.org; Wei Liu; Ian Campbell;
> > David Vrabel
> > Subject: Re: [PATCH net v3] xen-netback: fix fragment detection in checksum
> > setup
> > 
> > From: Paul Durrant <paul.durrant@citrix.com>
> > Date: Fri, 29 Nov 2013 10:52:08 +0000
> > 
> > > @@ -1166,15 +1166,27 @@ static int checksum_setup_ip(struct xenvif *vif,
> > struct sk_buff *skb,
> > >  	struct iphdr *iph = (void *)skb->data;
> > >  	unsigned int header_size;
> > >  	unsigned int off;
> > > +	bool fragment;
> > >  	int err = -EPROTO;
> > >
> > > +	fragment = false;
> > > +
> > >  	off = sizeof(struct iphdr);
> > >
> > >  	header_size = skb->network_header + off + MAX_IPOPTLEN;
> > >  	maybe_pull_tail(skb, header_size);
> > >
> > > +	if (iph->frag_off & htons(IP_OFFSET | IP_MF))
> > > +		fragment = true;
> > 
> > This function has a serious problem.
> > 
> > maybe_pull_tail() can change skb->data, therefore this "iph" pointer
> > can become invalid, you're essentially dereferencing garbage if
> > maybe_pull_tail() actually does any work.
> 
> Ok. Clearly I'm misunderstanding what __pskb_pull_tail() does then. I
> was under the impression that it moved skb->tail on but left skb->data
> alone (which is what I want to do). I will have another look.
[...]

A pull does not change the offset of skb->data but it may need to
expand, i.e. reallocate, the skb head area.  The kernel-doc states
clearly that this can happen.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

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

end of thread, other threads:[~2013-12-02 17:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-29 10:52 [PATCH net v3] xen-netback: fix fragment detection in checksum setup Paul Durrant
2013-11-30 21:13 ` David Miller
2013-12-02  9:45   ` Paul Durrant
2013-12-02 17:27     ` Ben Hutchings

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).