diff options
author | David Lebrun <david.lebrun@uclouvain.be> | 2017-04-16 12:27:14 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-17 21:33:53 +0200 |
commit | af3b5158b89d3bab9be881113417558c71b71ca4 (patch) | |
tree | 1b778313ea8d525310ccda4fe773bcf440474fe3 /net/ipv6/seg6_iptunnel.c | |
parent | gso: Validate assumption of frag_list segementation (diff) | |
download | linux-af3b5158b89d3bab9be881113417558c71b71ca4.tar.xz linux-af3b5158b89d3bab9be881113417558c71b71ca4.zip |
ipv6: sr: fix BUG due to headroom too small after SRH push
When a locally generated packet receives an SRH with two or more segments,
the remaining headroom is too small to push an ethernet header. This patch
ensures that the headroom is large enough after SRH push.
The BUG generated the following trace.
[ 192.950285] skbuff: skb_under_panic: text:ffffffff81809675 len:198 put:14 head:ffff88006f306400 data:ffff88006f3063fa tail:0xc0 end:0x2c0 dev:A-1
[ 192.952456] ------------[ cut here ]------------
[ 192.953218] kernel BUG at net/core/skbuff.c:105!
[ 192.953411] invalid opcode: 0000 [#1] PREEMPT SMP
[ 192.953411] Modules linked in:
[ 192.953411] CPU: 5 PID: 3433 Comm: ping6 Not tainted 4.11.0-rc3+ #237
[ 192.953411] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.10.1-0-g8891697-prebuilt.qemu-project.org 04/01/2014
[ 192.953411] task: ffff88007c2d42c0 task.stack: ffffc90000ef4000
[ 192.953411] RIP: 0010:skb_panic+0x61/0x70
[ 192.953411] RSP: 0018:ffffc90000ef7900 EFLAGS: 00010286
[ 192.953411] RAX: 0000000000000085 RBX: 00000000000086dd RCX: 0000000000000201
[ 192.953411] RDX: 0000000080000201 RSI: ffffffff81d104c5 RDI: 00000000ffffffff
[ 192.953411] RBP: ffffc90000ef7920 R08: 0000000000000001 R09: 0000000000000000
[ 192.953411] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
[ 192.953411] R13: ffff88007c5a4000 R14: ffff88007b363d80 R15: 00000000000000b8
[ 192.953411] FS: 00007f94b558b700(0000) GS:ffff88007fd40000(0000) knlGS:0000000000000000
[ 192.953411] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 192.953411] CR2: 00007fff5ecd5080 CR3: 0000000074141000 CR4: 00000000001406e0
[ 192.953411] Call Trace:
[ 192.953411] skb_push+0x3b/0x40
[ 192.953411] eth_header+0x25/0xc0
[ 192.953411] neigh_resolve_output+0x168/0x230
[ 192.953411] ? ip6_finish_output2+0x242/0x8f0
[ 192.953411] ip6_finish_output2+0x242/0x8f0
[ 192.953411] ? ip6_finish_output2+0x76/0x8f0
[ 192.953411] ip6_finish_output+0xa8/0x1d0
[ 192.953411] ip6_output+0x64/0x2d0
[ 192.953411] ? ip6_output+0x73/0x2d0
[ 192.953411] ? ip6_dst_check+0xb5/0xc0
[ 192.953411] ? dst_cache_per_cpu_get.isra.2+0x40/0x80
[ 192.953411] seg6_output+0xb0/0x220
[ 192.953411] lwtunnel_output+0xcf/0x210
[ 192.953411] ? lwtunnel_output+0x59/0x210
[ 192.953411] ip6_local_out+0x38/0x70
[ 192.953411] ip6_send_skb+0x2a/0xb0
[ 192.953411] ip6_push_pending_frames+0x48/0x50
[ 192.953411] rawv6_sendmsg+0xa39/0xf10
[ 192.953411] ? __lock_acquire+0x489/0x890
[ 192.953411] ? __mutex_lock+0x1fc/0x970
[ 192.953411] ? __lock_acquire+0x489/0x890
[ 192.953411] ? __mutex_lock+0x1fc/0x970
[ 192.953411] ? tty_ioctl+0x283/0xec0
[ 192.953411] inet_sendmsg+0x45/0x1d0
[ 192.953411] ? _copy_from_user+0x54/0x80
[ 192.953411] sock_sendmsg+0x33/0x40
[ 192.953411] SYSC_sendto+0xef/0x170
[ 192.953411] ? entry_SYSCALL_64_fastpath+0x5/0xc2
[ 192.953411] ? trace_hardirqs_on_caller+0x12b/0x1b0
[ 192.953411] ? trace_hardirqs_on_thunk+0x1a/0x1c
[ 192.953411] SyS_sendto+0x9/0x10
[ 192.953411] entry_SYSCALL_64_fastpath+0x1f/0xc2
[ 192.953411] RIP: 0033:0x7f94b453db33
[ 192.953411] RSP: 002b:00007fff5ecd0578 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
[ 192.953411] RAX: ffffffffffffffda RBX: 00007fff5ecd16e0 RCX: 00007f94b453db33
[ 192.953411] RDX: 0000000000000040 RSI: 000055a78352e9c0 RDI: 0000000000000003
[ 192.953411] RBP: 00007fff5ecd1690 R08: 000055a78352c940 R09: 000000000000001c
[ 192.953411] R10: 0000000000000000 R11: 0000000000000246 R12: 000055a783321e10
[ 192.953411] R13: 000055a7839890c0 R14: 0000000000000004 R15: 0000000000000000
[ 192.953411] Code: 00 00 48 89 44 24 10 8b 87 c4 00 00 00 48 89 44 24 08 48 8b 87 d8 00 00 00 48 c7 c7 90 58 d2 81 48 89 04 24 31 c0 e8 4f 70 9a ff <0f> 0b 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 48 8b 97 d8 00 00
[ 192.953411] RIP: skb_panic+0x61/0x70 RSP: ffffc90000ef7900
[ 193.000186] ---[ end trace bd0b89fabdf2f92c ]---
[ 193.000951] Kernel panic - not syncing: Fatal exception in interrupt
[ 193.001137] Kernel Offset: disabled
[ 193.001169] ---[ end Kernel panic - not syncing: Fatal exception in interrupt
Fixes: 19d5a26f5ef8de5dcb78799feaf404d717b1aac3 ("ipv6: sr: expand skb head only if necessary")
Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/seg6_iptunnel.c')
-rw-r--r-- | net/ipv6/seg6_iptunnel.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 7436a4a62f3e..6a495490d43e 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -265,6 +265,10 @@ static int seg6_input(struct sk_buff *skb) skb_dst_set(skb, dst); } + err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); + if (unlikely(err)) + return err; + return dst_input(skb); } @@ -310,6 +314,10 @@ static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb) skb_dst_drop(skb); skb_dst_set(skb, dst); + err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); + if (unlikely(err)) + goto drop; + return dst_output(net, sk, skb); drop: kfree_skb(skb); |