All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] net: Fix resetting network_header in neigh_resolve_output and neigh_connected_output
@ 2016-06-23 11:39 Abdelrhman Ahmed
  2016-06-27 14:10 ` David Miller
  0 siblings, 1 reply; 4+ messages in thread
From: Abdelrhman Ahmed @ 2016-06-23 11:39 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-kernel

neigh_resolve_output and neigh_connected_output resets the skb to network_header because of the retry loop and this reset will pull down the data pointer to the network header in the first iteration then hardware header will be added, but it will overwrite any data which is inserted between network header and hardware header (for example by netfilter hooks) only for the first packet(s) before using cached hardware header as neigh_hh_output (which is called for using cached hardware header) does not reset to the network header.

The fix is to reset with reference to skb's data before loop instead of network header.

Fixes: e1f165032c8b ("net: Fix skb_under_panic oops in neigh_resolve_output")
Signed-off-by: Abdelrhman Ahmed <ab@abahmed.com>
---
 net/core/neighbour.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 29dd8cc..7aac242 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1293,15 +1293,19 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
 	int rc = 0;
 
 	if (!neigh_event_send(neigh, skb)) {
-		int err;
+		int err, offset;
 		struct net_device *dev = neigh->dev;
+		unsigned char *data;
 		unsigned int seq;
 
 		if (dev->header_ops->cache && !neigh->hh.hh_len)
 			neigh_hh_init(neigh);
 
+		data = skb->data;
+
 		do {
-			__skb_pull(skb, skb_network_offset(skb));
+			offset = data - skb->data;
+			__skb_pull(skb, offset);
 			seq = read_seqbegin(&neigh->ha_lock);
 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
 					      neigh->ha, NULL, skb->len);
@@ -1326,11 +1330,15 @@ EXPORT_SYMBOL(neigh_resolve_output);
 int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
 {
 	struct net_device *dev = neigh->dev;
+	unsigned char *data;
 	unsigned int seq;
-	int err;
+	int err, offset;
+
+	data = skb->data;
 
 	do {
-		__skb_pull(skb, skb_network_offset(skb));
+		offset = data - skb->data;
+		__skb_pull(skb, offset);
 		seq = read_seqbegin(&neigh->ha_lock);
 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
 				      neigh->ha, NULL, skb->len);
-- 
1.9.1

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

* Re: [PATCH] net: Fix resetting network_header in neigh_resolve_output and neigh_connected_output
  2016-06-23 11:39 [PATCH] net: Fix resetting network_header in neigh_resolve_output and neigh_connected_output Abdelrhman Ahmed
@ 2016-06-27 14:10 ` David Miller
  2016-06-27 14:28   ` Abdelrhman Ahmed
  0 siblings, 1 reply; 4+ messages in thread
From: David Miller @ 2016-06-27 14:10 UTC (permalink / raw)
  To: ab; +Cc: netdev, linux-kernel

From: Abdelrhman Ahmed <ab@abahmed.com>
Date: Thu, 23 Jun 2016 13:39:24 +0200

> neigh_resolve_output and neigh_connected_output resets the skb to network_header because of the retry loop and this reset will pull down the data pointer to the network header in the first iteration then hardware header will be added, but it will overwrite any data which is inserted between network header and hardware header (for example by netfilter hooks) only for the first packet(s) before using cached hardware header as neigh_hh_output (which is called for using cached hardware header) does not reset to the network header.

Please format your text properly into ~80 character long lines.

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

* Re: [PATCH] net: Fix resetting network_header in neigh_resolve_output and neigh_connected_output
  2016-06-27 14:10 ` David Miller
@ 2016-06-27 14:28   ` Abdelrhman Ahmed
  2016-07-01 19:57     ` David Miller
  0 siblings, 1 reply; 4+ messages in thread
From: Abdelrhman Ahmed @ 2016-06-27 14:28 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-kernel

neigh_resolve_output and neigh_connected_output resets the skb to 
network_header because of the retry loop and this reset will pull down the
data pointer to the network header in the first iteration then hardware header
will be added, but it will overwrite any data which is inserted between network
header and hardware header (for example by netfilter hooks) only for the first
packet(s) before using cached hardware header as neigh_hh_output (which is
called for using cached hardware header) does not reset to the network header.

The fix is to reset with reference to skb's data before loop instead of network
header.

Fixes: e1f165032c8b ("net: Fix skb_under_panic oops in neigh_resolve_output")
Signed-off-by: Abdelrhman Ahmed <ab@abahmed.com>
---
 net/core/neighbour.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 29dd8cc..7aac242 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1293,15 +1293,19 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
 	int rc = 0;
 
 	if (!neigh_event_send(neigh, skb)) {
-		int err;
+		int err, offset;
 		struct net_device *dev = neigh->dev;
+		unsigned char *data;
 		unsigned int seq;
 
 		if (dev->header_ops->cache && !neigh->hh.hh_len)
 			neigh_hh_init(neigh);
 
+		data = skb->data;
+
 		do {
-			__skb_pull(skb, skb_network_offset(skb));
+			offset = data - skb->data;
+			__skb_pull(skb, offset);
 			seq = read_seqbegin(&neigh->ha_lock);
 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
 					      neigh->ha, NULL, skb->len);
@@ -1326,11 +1330,15 @@ EXPORT_SYMBOL(neigh_resolve_output);
 int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
 {
 	struct net_device *dev = neigh->dev;
+	unsigned char *data;
 	unsigned int seq;
-	int err;
+	int err, offset;
+
+	data = skb->data;
 
 	do {
-		__skb_pull(skb, skb_network_offset(skb));
+		offset = data - skb->data;
+		__skb_pull(skb, offset);
 		seq = read_seqbegin(&neigh->ha_lock);
 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
 				      neigh->ha, NULL, skb->len);
-- 
1.9.1

 ---- On Mon, 27 Jun 2016 16:10:32 +0200 David Miller <davem@davemloft.net> wrote ---- 
 > From: Abdelrhman Ahmed <ab@abahmed.com> 
 > Date: Thu, 23 Jun 2016 13:39:24 +0200 
 >  
 > > neigh_resolve_output and neigh_connected_output resets the skb to network_header because of the retry loop and this reset will pull down the data pointer to the network header in the first iteration then hardware header will be added, but it will overwrite any data which is inserted between network header and hardware header (for example by netfilter hooks) only for the first packet(s) before using cached hardware header as neigh_hh_output (which is called for using cached hardware header) does not reset to the network header. 
 >  
 > Please format your text properly into ~80 character long lines. 
 > 

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

* Re: [PATCH] net: Fix resetting network_header in neigh_resolve_output and neigh_connected_output
  2016-06-27 14:28   ` Abdelrhman Ahmed
@ 2016-07-01 19:57     ` David Miller
  0 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2016-07-01 19:57 UTC (permalink / raw)
  To: ab; +Cc: netdev, linux-kernel

From: Abdelrhman Ahmed <ab@abahmed.com>
Date: Mon, 27 Jun 2016 16:28:59 +0200

> @@ -1293,15 +1293,19 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
>  	int rc = 0;
>  
>  	if (!neigh_event_send(neigh, skb)) {
> -		int err;
> +		int err, offset;
>  		struct net_device *dev = neigh->dev;
> +		unsigned char *data;
>  		unsigned int seq;
>  
>  		if (dev->header_ops->cache && !neigh->hh.hh_len)
>  			neigh_hh_init(neigh);
>  
> +		data = skb->data;
> +
>  		do {
> -			__skb_pull(skb, skb_network_offset(skb));
> +			offset = data - skb->data;
> +			__skb_pull(skb, offset);

This is definitely not right, using skb->data for this.  It may work
for the cases you have tested but it is not generally correct.

You must use the skb network header.

You are just trying to avoid doing the pull more than once if we loop
right?  Then simply use a boolean to track that.

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

end of thread, other threads:[~2016-07-01 19:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-23 11:39 [PATCH] net: Fix resetting network_header in neigh_resolve_output and neigh_connected_output Abdelrhman Ahmed
2016-06-27 14:10 ` David Miller
2016-06-27 14:28   ` Abdelrhman Ahmed
2016-07-01 19:57     ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.