]>
Commit | Line | Data |
---|---|---|
0abab3b4 GKH |
1 | From 3cd2e0516746eec709d34c40865a060dab87d4a5 Mon Sep 17 00:00:00 2001 |
2 | From: Hannes Frederic Sowa <hannes@stressinduktion.org> | |
3 | Date: Mon, 1 Jul 2013 20:21:30 +0200 | |
4 | Subject: ipv6: call udp_push_pending_frames when uncorking a socket with AF_INET pending data | |
5 | ||
6 | From: Hannes Frederic Sowa <hannes@stressinduktion.org> | |
7 | ||
8 | [ Upstream commit 8822b64a0fa64a5dd1dfcf837c5b0be83f8c05d1 ] | |
9 | ||
10 | We accidentally call down to ip6_push_pending_frames when uncorking | |
11 | pending AF_INET data on a ipv6 socket. This results in the following | |
12 | splat (from Dave Jones): | |
13 | ||
14 | skbuff: skb_under_panic: text:ffffffff816765f6 len:48 put:40 head:ffff88013deb6df0 data:ffff88013deb6dec tail:0x2c end:0xc0 dev:<NULL> | |
15 | ------------[ cut here ]------------ | |
16 | kernel BUG at net/core/skbuff.c:126! | |
17 | invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC | |
18 | Modules linked in: dccp_ipv4 dccp 8021q garp bridge stp dlci mpoa snd_seq_dummy sctp fuse hidp tun bnep nfnetlink scsi_transport_iscsi rfcomm can_raw can_bcm af_802154 appletalk caif_socket can caif ipt_ULOG x25 rose af_key pppoe pppox ipx phonet irda llc2 ppp_generic slhc p8023 psnap p8022 llc crc_ccitt atm bluetooth | |
19 | +netrom ax25 nfc rfkill rds af_rxrpc coretemp hwmon kvm_intel kvm crc32c_intel snd_hda_codec_realtek ghash_clmulni_intel microcode pcspkr snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep usb_debug snd_seq snd_seq_device snd_pcm e1000e snd_page_alloc snd_timer ptp snd pps_core soundcore xfs libcrc32c | |
20 | CPU: 2 PID: 8095 Comm: trinity-child2 Not tainted 3.10.0-rc7+ #37 | |
21 | task: ffff8801f52c2520 ti: ffff8801e6430000 task.ti: ffff8801e6430000 | |
22 | RIP: 0010:[<ffffffff816e759c>] [<ffffffff816e759c>] skb_panic+0x63/0x65 | |
23 | RSP: 0018:ffff8801e6431de8 EFLAGS: 00010282 | |
24 | RAX: 0000000000000086 RBX: ffff8802353d3cc0 RCX: 0000000000000006 | |
25 | RDX: 0000000000003b90 RSI: ffff8801f52c2ca0 RDI: ffff8801f52c2520 | |
26 | RBP: ffff8801e6431e08 R08: 0000000000000000 R09: 0000000000000000 | |
27 | R10: 0000000000000001 R11: 0000000000000001 R12: ffff88022ea0c800 | |
28 | R13: ffff88022ea0cdf8 R14: ffff8802353ecb40 R15: ffffffff81cc7800 | |
29 | FS: 00007f5720a10740(0000) GS:ffff880244c00000(0000) knlGS:0000000000000000 | |
30 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | |
31 | CR2: 0000000005862000 CR3: 000000022843c000 CR4: 00000000001407e0 | |
32 | DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | |
33 | DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000600 | |
34 | Stack: | |
35 | ffff88013deb6dec 000000000000002c 00000000000000c0 ffffffff81a3f6e4 | |
36 | ffff8801e6431e18 ffffffff8159a9aa ffff8801e6431e90 ffffffff816765f6 | |
37 | ffffffff810b756b 0000000700000002 ffff8801e6431e40 0000fea9292aa8c0 | |
38 | Call Trace: | |
39 | [<ffffffff8159a9aa>] skb_push+0x3a/0x40 | |
40 | [<ffffffff816765f6>] ip6_push_pending_frames+0x1f6/0x4d0 | |
41 | [<ffffffff810b756b>] ? mark_held_locks+0xbb/0x140 | |
42 | [<ffffffff81694919>] udp_v6_push_pending_frames+0x2b9/0x3d0 | |
43 | [<ffffffff81694660>] ? udplite_getfrag+0x20/0x20 | |
44 | [<ffffffff8162092a>] udp_lib_setsockopt+0x1aa/0x1f0 | |
45 | [<ffffffff811cc5e7>] ? fget_light+0x387/0x4f0 | |
46 | [<ffffffff816958a4>] udpv6_setsockopt+0x34/0x40 | |
47 | [<ffffffff815949f4>] sock_common_setsockopt+0x14/0x20 | |
48 | [<ffffffff81593c31>] SyS_setsockopt+0x71/0xd0 | |
49 | [<ffffffff816f5d54>] tracesys+0xdd/0xe2 | |
50 | Code: 00 00 48 89 44 24 10 8b 87 d8 00 00 00 48 89 44 24 08 48 8b 87 e8 00 00 00 48 c7 c7 c0 04 aa 81 48 89 04 24 31 c0 e8 e1 7e ff ff <0f> 0b 55 48 89 e5 0f 0b 55 48 89 e5 0f 0b 55 48 89 e5 0f 0b 55 | |
51 | RIP [<ffffffff816e759c>] skb_panic+0x63/0x65 | |
52 | RSP <ffff8801e6431de8> | |
53 | ||
54 | This patch adds a check if the pending data is of address family AF_INET | |
55 | and directly calls udp_push_ending_frames from udp_v6_push_pending_frames | |
56 | if that is the case. | |
57 | ||
58 | This bug was found by Dave Jones with trinity. | |
59 | ||
60 | (Also move the initialization of fl6 below the AF_INET check, even if | |
61 | not strictly necessary.) | |
62 | ||
63 | Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> | |
64 | Cc: Dave Jones <davej@redhat.com> | |
65 | Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | |
66 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
67 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
68 | --- | |
69 | include/net/udp.h | 1 + | |
70 | net/ipv4/udp.c | 3 ++- | |
71 | net/ipv6/udp.c | 7 ++++++- | |
72 | 3 files changed, 9 insertions(+), 2 deletions(-) | |
73 | ||
74 | --- a/include/net/udp.h | |
75 | +++ b/include/net/udp.h | |
76 | @@ -180,6 +180,7 @@ extern int udp_get_port(struct sock *sk, | |
77 | extern void udp_err(struct sk_buff *, u32); | |
78 | extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, | |
79 | struct msghdr *msg, size_t len); | |
80 | +extern int udp_push_pending_frames(struct sock *sk); | |
81 | extern void udp_flush_pending_frames(struct sock *sk); | |
82 | extern int udp_rcv(struct sk_buff *skb); | |
83 | extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); | |
84 | --- a/net/ipv4/udp.c | |
85 | +++ b/net/ipv4/udp.c | |
86 | @@ -765,7 +765,7 @@ send: | |
87 | /* | |
88 | * Push out all pending data as one UDP datagram. Socket is locked. | |
89 | */ | |
90 | -static int udp_push_pending_frames(struct sock *sk) | |
91 | +int udp_push_pending_frames(struct sock *sk) | |
92 | { | |
93 | struct udp_sock *up = udp_sk(sk); | |
94 | struct inet_sock *inet = inet_sk(sk); | |
95 | @@ -784,6 +784,7 @@ out: | |
96 | up->pending = 0; | |
97 | return err; | |
98 | } | |
99 | +EXPORT_SYMBOL(udp_push_pending_frames); | |
100 | ||
101 | int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |
102 | size_t len) | |
103 | --- a/net/ipv6/udp.c | |
104 | +++ b/net/ipv6/udp.c | |
105 | @@ -892,11 +892,16 @@ static int udp_v6_push_pending_frames(st | |
106 | struct udphdr *uh; | |
107 | struct udp_sock *up = udp_sk(sk); | |
108 | struct inet_sock *inet = inet_sk(sk); | |
109 | - struct flowi6 *fl6 = &inet->cork.fl.u.ip6; | |
110 | + struct flowi6 *fl6; | |
111 | int err = 0; | |
112 | int is_udplite = IS_UDPLITE(sk); | |
113 | __wsum csum = 0; | |
114 | ||
115 | + if (up->pending == AF_INET) | |
116 | + return udp_push_pending_frames(sk); | |
117 | + | |
118 | + fl6 = &inet->cork.fl.u.ip6; | |
119 | + | |
120 | /* Grab the skbuff where UDP header space exists. */ | |
121 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) | |
122 | goto out; |