netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
@ 2011-01-02 20:18 Tomas Winkler
  2011-01-03  9:34 ` Johannes Berg
  0 siblings, 1 reply; 6+ messages in thread
From: Tomas Winkler @ 2011-01-02 20:18 UTC (permalink / raw)
  To: davem; +Cc: netdev, Tomas Winkler, Johannes Berg, Stephen Hemminger

use pskb_may_pull to access ipv6 header correctly for paged skbs
It was omitted in the bridge code leading to crash in blind
__skb_pull

this fixes bug https://bugzilla.kernel.org/show_bug.cgi?id=25202

Dec 15 14:36:40 User-PC hostapd: wlan0: STA 00:15:00:60:5d:34 IEEE 802.11: authenticated
Dec 15 14:36:40 User-PC hostapd: wlan0: STA 00:15:00:60:5d:34 IEEE 802.11: associated (aid 2)
Dec 15 14:36:40 User-PC hostapd: wlan0: STA 00:15:00:60:5d:34 RADIUS: starting accounting session 4D0608A3-00000005
Dec 15 14:36:41 User-PC kernel: [175576.120287] ------------[ cut here ]------------
Dec 15 14:36:41 User-PC kernel: [175576.120452] kernel BUG at include/linux/skbuff.h:1178!
Dec 15 14:36:41 User-PC kernel: [175576.120609] invalid opcode: 0000 [#1] SMP
Dec 15 14:36:41 User-PC kernel: [175576.120749] last sysfs file: /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/uevent
Dec 15 14:36:41 User-PC kernel: [175576.121035] Modules linked in: oprofile binfmt_misc bridge stp llc parport_pc ppdev arc4 iwlagn snd_hda_codec_realtek iwlcore i915 snd_hda_intel mac80211 joydev snd_hda_codec snd_hwdep snd_pcm snd_seq_midi drm_kms_helper snd_rawmidi drm snd_seq_midi_event snd_seq snd_timer snd_seq_device cfg80211 eeepc_wmi usbhid psmouse intel_agp i2c_algo_bit intel_gtt uvcvideo agpgart videodev sparse_keymap snd shpchp v4l1_compat lp hid video serio_raw soundcore output snd_page_alloc ahci libahci atl1c
Dec 15 14:36:41 User-PC kernel: [175576.122712]
Dec 15 14:36:41 User-PC kernel: [175576.122769] Pid: 0, comm: kworker/0:0 Tainted: G        W   2.6.37-rc5-wl+ #3 1015PE/1016P
Dec 15 14:36:41 User-PC kernel: [175576.123012] EIP: 0060:[<f83edd65>] EFLAGS: 00010283 CPU: 1
Dec 15 14:36:41 User-PC kernel: [175576.123193] EIP is at br_multicast_rcv+0xc95/0xe1c [bridge]
Dec 15 14:36:41 User-PC kernel: [175576.123362] EAX: 0000001c EBX: f5626318 ECX: 00000000 EDX: 00000000
Dec 15 14:36:41 User-PC kernel: [175576.123550] ESI: ec512262 EDI: f5626180 EBP: f60b5ca0 ESP: f60b5bd8
Dec 15 14:36:41 User-PC kernel: [175576.123737]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Dec 15 14:36:41 User-PC kernel: [175576.123902] Process kworker/0:0 (pid: 0, ti=f60b4000 task=f60a8000 task.ti=f60b0000)
Dec 15 14:36:41 User-PC kernel: [175576.124137] Stack:
Dec 15 14:36:41 User-PC kernel: [175576.124181]  ec556500 f6d06800 f60b5be8 c01087d8 ec512262 00000030 00000024 f5626180
Dec 15 14:36:41 User-PC kernel: [175576.124181]  f572c200 ef463440 f5626300 3affffff f6d06dd0 e60766a4 000000c4 f6d06860
Dec 15 14:36:41 User-PC kernel: [175576.124181]  ffffffff ec55652c 00000001 f6d06844 f60b5c64 c0138264 c016e451 c013e47d
Dec 15 14:36:41 User-PC kernel: [175576.124181] Call Trace:
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c01087d8>] ? sched_clock+0x8/0x10
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0138264>] ? enqueue_entity+0x174/0x440
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c016e451>] ? sched_clock_cpu+0x131/0x190
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c013e47d>] ? select_task_rq_fair+0x2ad/0x730
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0524fc1>] ? nf_iterate+0x71/0x90
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f83e4914>] ? br_handle_frame_finish+0x184/0x220 [bridge]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f83e4790>] ? br_handle_frame_finish+0x0/0x220 [bridge]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f83e46e9>] ? br_handle_frame+0x189/0x230 [bridge]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f83e4790>] ? br_handle_frame_finish+0x0/0x220 [bridge]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f83e4560>] ? br_handle_frame+0x0/0x230 [bridge]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c04ff026>] ? __netif_receive_skb+0x1b6/0x5b0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c04f7a30>] ? skb_copy_bits+0x110/0x210
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0503a7f>] ? netif_receive_skb+0x6f/0x80
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f82cb74c>] ? ieee80211_deliver_skb+0x8c/0x1a0 [mac80211]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f82cc836>] ? ieee80211_rx_handlers+0xeb6/0x1aa0 [mac80211]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c04ff1f0>] ? __netif_receive_skb+0x380/0x5b0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c016e242>] ? sched_clock_local+0xb2/0x190
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c012b688>] ? default_spin_lock_flags+0x8/0x10
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c05d83df>] ? _raw_spin_lock_irqsave+0x2f/0x50
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f82cd621>] ? ieee80211_prepare_and_rx_handle+0x201/0xa90 [mac80211]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f82ce154>] ? ieee80211_rx+0x2a4/0x830 [mac80211]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f815a8d6>] ? iwl_update_stats+0xa6/0x2a0 [iwlcore]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f8499212>] ? iwlagn_rx_reply_rx+0x292/0x3b0 [iwlagn]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c05d83df>] ? _raw_spin_lock_irqsave+0x2f/0x50
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f8483697>] ? iwl_rx_handle+0xe7/0x350 [iwlagn]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<f8486ab7>] ? iwl_irq_tasklet+0xf7/0x5c0 [iwlagn]
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c01aece1>] ? __rcu_process_callbacks+0x201/0x2d0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0150d05>] ? tasklet_action+0xc5/0x100
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0150a07>] ? __do_softirq+0x97/0x1d0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c05d910c>] ? nmi_stack_correct+0x2f/0x34
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0150970>] ? __do_softirq+0x0/0x1d0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  <IRQ>
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c01508f5>] ? irq_exit+0x65/0x70
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c05df062>] ? do_IRQ+0x52/0xc0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c01036b0>] ? common_interrupt+0x30/0x38
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c03a1fc2>] ? intel_idle+0xc2/0x160
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c04daebb>] ? cpuidle_idle_call+0x6b/0x100
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c0101dea>] ? cpu_idle+0x8a/0xf0
Dec 15 14:36:41 User-PC kernel: [175576.124181]  [<c05d2702>] ? start_secondary+0x1e8/0x1ee

Cc: David Miller <davem@davemloft.net>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: Implement David Miller's suggestion 
V3: Fix the mld_msg access:
	Length check was wrong and psk_may_pull performs itself the length check

 net/bridge/br_multicast.c |   24 ++++++++++++++++++------
 1 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index f19e347..6932a0c 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1469,15 +1469,16 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 	if (!skb2)
 		return -ENOMEM;
 
+
+	err = -EINVAL;
+	if (!pskb_may_pull(skb2, offset + sizeof(struct icmp6hdr)))
+		goto out_nopush;
+
 	len -= offset - skb_network_offset(skb2);
 
 	__skb_pull(skb2, offset);
 	skb_reset_transport_header(skb2);
 
-	err = -EINVAL;
-	if (!pskb_may_pull(skb2, sizeof(*icmp6h)))
-		goto out;
-
 	icmp6h = icmp6_hdr(skb2);
 
 	switch (icmp6h->icmp6_type) {
@@ -1516,7 +1517,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 	switch (icmp6h->icmp6_type) {
 	case ICMPV6_MGM_REPORT:
 	    {
-		struct mld_msg *mld = (struct mld_msg *)icmp6h;
+		struct mld_msg *mld;
+		if (!pskb_may_pull(skb2, sizeof(*mld))) {
+			err = -EINVAL;
+			goto out;
+		}
+		mld = (struct mld_msg *)icmp6h;
 		BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
 		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
 		break;
@@ -1529,13 +1535,19 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 		break;
 	case ICMPV6_MGM_REDUCTION:
 	    {
-		struct mld_msg *mld = (struct mld_msg *)icmp6h;
+		struct mld_msg *mld;
+		if (!pskb_may_pull(skb2, sizeof(*mld))) {
+			err = -EINVAL;
+			goto out;
+		}
+		mld = (struct mld_msg *)icmp6h;
 		br_ip6_multicast_leave_group(br, port, &mld->mld_mca);
 	    }
 	}
 
 out:
 	__skb_push(skb2, offset);
+out_nopush:
 	if (skb2 != skb)
 		kfree_skb(skb2);
 	return err;
-- 
1.7.3.4

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


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

* Re: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
  2011-01-02 20:18 [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs Tomas Winkler
@ 2011-01-03  9:34 ` Johannes Berg
  2011-01-03  9:43   ` Winkler, Tomas
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Berg @ 2011-01-03  9:34 UTC (permalink / raw)
  To: Tomas Winkler; +Cc: davem, netdev, Stephen Hemminger

On Sun, 2011-01-02 at 22:18 +0200, Tomas Winkler wrote:

>  	icmp6h = icmp6_hdr(skb2);
>  
>  	switch (icmp6h->icmp6_type) {
> @@ -1516,7 +1517,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
>  	switch (icmp6h->icmp6_type) {
>  	case ICMPV6_MGM_REPORT:
>  	    {
> -		struct mld_msg *mld = (struct mld_msg *)icmp6h;
> +		struct mld_msg *mld;
> +		if (!pskb_may_pull(skb2, sizeof(*mld))) {
> +			err = -EINVAL;
> +			goto out;
> +		}
> +		mld = (struct mld_msg *)icmp6h;

This (and the second instance) is incorrect afaict -- the pointer
"icmp6h" should be reloaded after the pskb_may_pull(), no?

Also, the "out_nopush" thing is pointless since the push is completely
unnecessary as "skb2 != skb" is always true.

johannes


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

* RE: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
  2011-01-03  9:34 ` Johannes Berg
@ 2011-01-03  9:43   ` Winkler, Tomas
  2011-01-03 10:04     ` Johannes Berg
  0 siblings, 1 reply; 6+ messages in thread
From: Winkler, Tomas @ 2011-01-03  9:43 UTC (permalink / raw)
  To: Johannes Berg
  Cc: davem@davemloft.net, netdev@vger.kernel.org, Stephen Hemminger



> -----Original Message-----
> From: Johannes Berg [mailto:johannes@sipsolutions.net]
> Sent: Monday, January 03, 2011 11:34 AM
> To: Winkler, Tomas
> Cc: davem@davemloft.net; netdev@vger.kernel.org; Stephen Hemminger
> Subject: Re: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
> 
> On Sun, 2011-01-02 at 22:18 +0200, Tomas Winkler wrote:
> 
> >  	icmp6h = icmp6_hdr(skb2);
> >
> >  	switch (icmp6h->icmp6_type) {
> > @@ -1516,7 +1517,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge
> *br,
> >  	switch (icmp6h->icmp6_type) {
> >  	case ICMPV6_MGM_REPORT:
> >  	    {
> > -		struct mld_msg *mld = (struct mld_msg *)icmp6h;
> > +		struct mld_msg *mld;
> > +		if (!pskb_may_pull(skb2, sizeof(*mld))) {
> > +			err = -EINVAL;
> > +			goto out;
> > +		}
> > +		mld = (struct mld_msg *)icmp6h;
> 
> This (and the second instance) is incorrect afaict -- the pointer
> "icmp6h" should be reloaded after the pskb_may_pull(), no?

mld_msg is bigger than icmp6h by sizeof(in6_addr) so we have to try pull again a bigger chunk. 

> 
> Also, the "out_nopush" thing is pointless since the push is completely
> unnecessary as "skb2 != skb" is always true.

You are right if skb_clone doesn't return the same pointer then yes. Shame, but I'm not a sbk expert. I'm diving into it now.

Thanks
Tomas
---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.

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

* RE: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
  2011-01-03  9:43   ` Winkler, Tomas
@ 2011-01-03 10:04     ` Johannes Berg
  2011-01-03 10:17       ` Winkler, Tomas
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Berg @ 2011-01-03 10:04 UTC (permalink / raw)
  To: Winkler, Tomas
  Cc: davem@davemloft.net, netdev@vger.kernel.org, Stephen Hemminger

On Mon, 2011-01-03 at 11:43 +0200, Winkler, Tomas wrote:

> > > -		struct mld_msg *mld = (struct mld_msg *)icmp6h;
> > > +		struct mld_msg *mld;
> > > +		if (!pskb_may_pull(skb2, sizeof(*mld))) {
> > > +			err = -EINVAL;
> > > +			goto out;
> > > +		}
> > > +		mld = (struct mld_msg *)icmp6h;
> > 
> > This (and the second instance) is incorrect afaict -- the pointer
> > "icmp6h" should be reloaded after the pskb_may_pull(), no?
> 
> mld_msg is bigger than icmp6h by sizeof(in6_addr) so we have to try pull again a bigger chunk. 

Right, I know, the pskb_may_pull() is needed, but I believe you need to
re-calculate icmp6h here.

> > Also, the "out_nopush" thing is pointless since the push is completely
> > unnecessary as "skb2 != skb" is always true.
> 
> You are right if skb_clone doesn't return the same pointer then yes.
> Shame, but I'm not a sbk expert. I'm diving into it now.

I'm pretty sure it's guaranteed to return a new pointer.

johannes


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

* RE: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
  2011-01-03 10:04     ` Johannes Berg
@ 2011-01-03 10:17       ` Winkler, Tomas
  2011-01-03 10:41         ` Johannes Berg
  0 siblings, 1 reply; 6+ messages in thread
From: Winkler, Tomas @ 2011-01-03 10:17 UTC (permalink / raw)
  To: Johannes Berg
  Cc: davem@davemloft.net, netdev@vger.kernel.org, Stephen Hemminger



> -----Original Message-----
> From: Johannes Berg [mailto:johannes@sipsolutions.net]
> Sent: Monday, January 03, 2011 12:04 PM
> To: Winkler, Tomas
> Cc: davem@davemloft.net; netdev@vger.kernel.org; Stephen Hemminger
> Subject: RE: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
> 
> On Mon, 2011-01-03 at 11:43 +0200, Winkler, Tomas wrote:
> 
> > > > -		struct mld_msg *mld = (struct mld_msg *)icmp6h;
> > > > +		struct mld_msg *mld;
> > > > +		if (!pskb_may_pull(skb2, sizeof(*mld))) {
> > > > +			err = -EINVAL;
> > > > +			goto out;
> > > > +		}
> > > > +		mld = (struct mld_msg *)icmp6h;
> > >
> > > This (and the second instance) is incorrect afaict -- the pointer
> > > "icmp6h" should be reloaded after the pskb_may_pull(), no?
> >
> > mld_msg is bigger than icmp6h by sizeof(in6_addr) so we have to try pull
> again a bigger chunk.
> 
> Right, I know, the pskb_may_pull() is needed, but I believe you need to
> re-calculate icmp6h here.

You are right, it can be moved to new memory buffer.

Probably something like that will do it:

if (!pskb_may_pull(skb2, sizeof(*mld))) {
	err = -EINVAL;
	goto out;
}
mld = (struct mld_msg *)skb_transport_header(skb2) 

> 
> > > Also, the "out_nopush" thing is pointless since the push is completely
> > > unnecessary as "skb2 != skb" is always true.
> >
> > You are right if skb_clone doesn't return the same pointer then yes.
> > Shame, but I'm not a sbk expert. I'm diving into it now.
> 
> I'm pretty sure it's guaranteed to return a new pointer.

Right, it either returns skb + 1 or new one from the cache. We can drop the nopush section.

Thanks
Tomas
---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.

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

* RE: [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs
  2011-01-03 10:17       ` Winkler, Tomas
@ 2011-01-03 10:41         ` Johannes Berg
  0 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2011-01-03 10:41 UTC (permalink / raw)
  To: Winkler, Tomas
  Cc: davem@davemloft.net, netdev@vger.kernel.org, Stephen Hemminger

On Mon, 2011-01-03 at 12:17 +0200, Winkler, Tomas wrote:

> > > > > -		struct mld_msg *mld = (struct mld_msg *)icmp6h;
> > > > > +		struct mld_msg *mld;
> > > > > +		if (!pskb_may_pull(skb2, sizeof(*mld))) {
> > > > > +			err = -EINVAL;
> > > > > +			goto out;
> > > > > +		}
> > > > > +		mld = (struct mld_msg *)icmp6h;
> > > >
> > > > This (and the second instance) is incorrect afaict -- the pointer
> > > > "icmp6h" should be reloaded after the pskb_may_pull(), no?
> > >
> > > mld_msg is bigger than icmp6h by sizeof(in6_addr) so we have to try pull
> > again a bigger chunk.
> > 
> > Right, I know, the pskb_may_pull() is needed, but I believe you need to
> > re-calculate icmp6h here.
> 
> You are right, it can be moved to new memory buffer.
> 
> Probably something like that will do it:
> 
> if (!pskb_may_pull(skb2, sizeof(*mld))) {
> 	err = -EINVAL;
> 	goto out;
> }
> mld = (struct mld_msg *)skb_transport_header(skb2) 

Yeah, that'll do, although I see more callers of icmp6_hdr() here
instead even for mld stuff (which is an inline though doing just this)

johannes


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

end of thread, other threads:[~2011-01-03 10:42 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-02 20:18 [PATCH 1/1 V3] bridge: fix br_multicast_ipv6_rcv for paged skbs Tomas Winkler
2011-01-03  9:34 ` Johannes Berg
2011-01-03  9:43   ` Winkler, Tomas
2011-01-03 10:04     ` Johannes Berg
2011-01-03 10:17       ` Winkler, Tomas
2011-01-03 10:41         ` Johannes Berg

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