icmp: icmp_sk() should not use smp_processor_id() in preemptible code

Pass namespace into icmp_xmit_lock, obtain socket inside and return
it as a result for caller.

Thanks Alexey Dobryan for this report:

Steps to reproduce:

CONFIG_PREEMPT=y
CONFIG_DEBUG_PREEMPT=y
tracepath <something>

BUG: using smp_processor_id() in preemptible [00000000] code: tracepath/3205
caller is icmp_sk+0x15/0x30
Pid: 3205, comm: tracepath Not tainted 2.6.27-rc4 #1

Call Trace:
[<ffffffff8031af14>] debug_smp_processor_id+0xe4/0xf0
[<ffffffff80409405>] icmp_sk+0x15/0x30
[<ffffffff8040a17b>] icmp_send+0x4b/0x3f0
[<ffffffff8025a415>] ? trace_hardirqs_on_caller+0xd5/0x160
[<ffffffff8025a4ad>] ? trace_hardirqs_on+0xd/0x10
[<ffffffff8023a475>] ? local_bh_enable_ip+0x95/0x110
[<ffffffff804285b9>] ? _spin_unlock_bh+0x39/0x40
[<ffffffff8025a26c>] ? mark_held_locks+0x4c/0x90
[<ffffffff8025a4ad>] ? trace_hardirqs_on+0xd/0x10
[<ffffffff8025a415>] ? trace_hardirqs_on_caller+0xd5/0x160
[<ffffffff803e91b4>] ip_fragment+0x8d4/0x900
[<ffffffff803e7030>] ? ip_finish_output2+0x0/0x290
[<ffffffff803e91e0>] ? ip_finish_output+0x0/0x60
[<ffffffff803e6650>] ? dst_output+0x0/0x10
[<ffffffff803e922c>] ip_finish_output+0x4c/0x60
[<ffffffff803e92e3>] ip_output+0xa3/0xf0
[<ffffffff803e68d0>] ip_local_out+0x20/0x30
[<ffffffff803e753f>] ip_push_pending_frames+0x27f/0x400
[<ffffffff80406313>] udp_push_pending_frames+0x233/0x3d0
[<ffffffff804067d1>] udp_sendmsg+0x321/0x6f0
[<ffffffff8040d155>] inet_sendmsg+0x45/0x80
[<ffffffff803b967f>] sock_sendmsg+0xdf/0x110
[<ffffffff8024a100>] ? autoremove_wake_function+0x0/0x40
[<ffffffff80257ce5>] ? validate_chain+0x415/0x1010
[<ffffffff8027dc10>] ? __do_fault+0x140/0x450
[<ffffffff802597d0>] ? __lock_acquire+0x260/0x590
[<ffffffff803b9e55>] ? sockfd_lookup_light+0x45/0x80
[<ffffffff803ba50a>] sys_sendto+0xea/0x120
[<ffffffff80428e42>] ? _spin_unlock_irqrestore+0x42/0x80
[<ffffffff803134bc>] ? __up_read+0x4c/0xb0
[<ffffffff8024e0c6>] ? up_read+0x26/0x30
[<ffffffff8020b8bb>] system_call_fastpath+0x16/0x1b

icmp6_sk() is similar.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Denis V. Lunev and committed by David S. Miller fdc0bde9 f6e0b239

+26 -19
+14 -8
net/ipv4/icmp.c
··· 204 return net->ipv4.icmp_sk[smp_processor_id()]; 205 } 206 207 - static inline int icmp_xmit_lock(struct sock *sk) 208 { 209 local_bh_disable(); 210 211 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { 212 /* This can happen if the output path signals a 213 * dst_link_failure() for an outgoing ICMP packet. 214 */ 215 local_bh_enable(); 216 - return 1; 217 } 218 - return 0; 219 } 220 221 static inline void icmp_xmit_unlock(struct sock *sk) ··· 358 struct ipcm_cookie ipc; 359 struct rtable *rt = skb->rtable; 360 struct net *net = dev_net(rt->u.dst.dev); 361 - struct sock *sk = icmp_sk(net); 362 - struct inet_sock *inet = inet_sk(sk); 363 __be32 daddr; 364 365 if (ip_options_echo(&icmp_param->replyopts, skb)) 366 return; 367 368 - if (icmp_xmit_lock(sk)) 369 return; 370 371 icmp_param->data.icmph.checksum = 0; 372 ··· 425 if (!rt) 426 goto out; 427 net = dev_net(rt->u.dst.dev); 428 - sk = icmp_sk(net); 429 430 /* 431 * Find the original header. It is expected to be valid, of course. ··· 488 } 489 } 490 491 - if (icmp_xmit_lock(sk)) 492 return; 493 494 /*
··· 204 return net->ipv4.icmp_sk[smp_processor_id()]; 205 } 206 207 + static inline struct sock *icmp_xmit_lock(struct net *net) 208 { 209 + struct sock *sk; 210 + 211 local_bh_disable(); 212 + 213 + sk = icmp_sk(net); 214 215 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { 216 /* This can happen if the output path signals a 217 * dst_link_failure() for an outgoing ICMP packet. 218 */ 219 local_bh_enable(); 220 + return NULL; 221 } 222 + return sk; 223 } 224 225 static inline void icmp_xmit_unlock(struct sock *sk) ··· 354 struct ipcm_cookie ipc; 355 struct rtable *rt = skb->rtable; 356 struct net *net = dev_net(rt->u.dst.dev); 357 + struct sock *sk; 358 + struct inet_sock *inet; 359 __be32 daddr; 360 361 if (ip_options_echo(&icmp_param->replyopts, skb)) 362 return; 363 364 + sk = icmp_xmit_lock(net); 365 + if (sk == NULL) 366 return; 367 + inet = inet_sk(sk); 368 369 icmp_param->data.icmph.checksum = 0; 370 ··· 419 if (!rt) 420 goto out; 421 net = dev_net(rt->u.dst.dev); 422 423 /* 424 * Find the original header. It is expected to be valid, of course. ··· 483 } 484 } 485 486 + sk = icmp_xmit_lock(net); 487 + if (sk == NULL) 488 return; 489 490 /*
+12 -11
net/ipv6/icmp.c
··· 91 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 92 }; 93 94 - static __inline__ int icmpv6_xmit_lock(struct sock *sk) 95 { 96 local_bh_disable(); 97 98 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { 99 /* This can happen if the output path (f.e. SIT or 100 * ip6ip6 tunnel) signals dst_link_failure() for an 101 * outgoing ICMP6 packet. 102 */ 103 local_bh_enable(); 104 - return 1; 105 } 106 - return 0; 107 } 108 109 static __inline__ void icmpv6_xmit_unlock(struct sock *sk) ··· 395 fl.fl_icmp_code = code; 396 security_skb_classify_flow(skb, &fl); 397 398 - sk = icmpv6_sk(net); 399 - np = inet6_sk(sk); 400 - 401 - if (icmpv6_xmit_lock(sk)) 402 return; 403 404 if (!icmpv6_xrlim_allow(sk, type, &fl)) 405 goto out; ··· 541 fl.fl_icmp_type = ICMPV6_ECHO_REPLY; 542 security_skb_classify_flow(skb, &fl); 543 544 - sk = icmpv6_sk(net); 545 - np = inet6_sk(sk); 546 - 547 - if (icmpv6_xmit_lock(sk)) 548 return; 549 550 if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) 551 fl.oif = np->mcast_oif;
··· 91 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 92 }; 93 94 + static __inline__ struct sock *icmpv6_xmit_lock(struct net *net) 95 { 96 + struct sock *sk; 97 + 98 local_bh_disable(); 99 100 + sk = icmpv6_sk(net); 101 if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { 102 /* This can happen if the output path (f.e. SIT or 103 * ip6ip6 tunnel) signals dst_link_failure() for an 104 * outgoing ICMP6 packet. 105 */ 106 local_bh_enable(); 107 + return NULL; 108 } 109 + return sk; 110 } 111 112 static __inline__ void icmpv6_xmit_unlock(struct sock *sk) ··· 392 fl.fl_icmp_code = code; 393 security_skb_classify_flow(skb, &fl); 394 395 + sk = icmpv6_xmit_lock(net); 396 + if (sk == NULL) 397 return; 398 + np = inet6_sk(sk); 399 400 if (!icmpv6_xrlim_allow(sk, type, &fl)) 401 goto out; ··· 539 fl.fl_icmp_type = ICMPV6_ECHO_REPLY; 540 security_skb_classify_flow(skb, &fl); 541 542 + sk = icmpv6_xmit_lock(net); 543 + if (sk == NULL) 544 return; 545 + np = inet6_sk(sk); 546 547 if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) 548 fl.oif = np->mcast_oif;