Commit 84427d53 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller

[IPV6]: Ensure to use icmpv6_socket in non-preemptive context.

We saw following trace several times:

|BUG: using smp_processor_id() in preemptible [00000001] code: httpd/30137
|caller is icmpv6_send+0x23/0x540
| [<c01ad63b>] smp_processor_id+0x9b/0xb8
| [<c02993e7>] icmpv6_send+0x23/0x540

This is because of icmpv6_socket, which is the only one user of
smp_processor_id() in icmpv6_send(), AFAIK.

Since it should be used in non-preemptive context,
let's defer the dereference after disabling preemption
(by icmpv6_xmit_lock()).
Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 979b6c13
...@@ -277,8 +277,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ...@@ -277,8 +277,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
{ {
struct inet6_dev *idev = NULL; struct inet6_dev *idev = NULL;
struct ipv6hdr *hdr = skb->nh.ipv6h; struct ipv6hdr *hdr = skb->nh.ipv6h;
struct sock *sk = icmpv6_socket->sk; struct sock *sk;
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np;
struct in6_addr *saddr = NULL; struct in6_addr *saddr = NULL;
struct dst_entry *dst; struct dst_entry *dst;
struct icmp6hdr tmp_hdr; struct icmp6hdr tmp_hdr;
...@@ -358,6 +358,9 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ...@@ -358,6 +358,9 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
if (icmpv6_xmit_lock()) if (icmpv6_xmit_lock())
return; return;
sk = icmpv6_socket->sk;
np = inet6_sk(sk);
if (!icmpv6_xrlim_allow(sk, type, &fl)) if (!icmpv6_xrlim_allow(sk, type, &fl))
goto out; goto out;
...@@ -423,9 +426,9 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ...@@ -423,9 +426,9 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
static void icmpv6_echo_reply(struct sk_buff *skb) static void icmpv6_echo_reply(struct sk_buff *skb)
{ {
struct sock *sk = icmpv6_socket->sk; struct sock *sk;
struct inet6_dev *idev; struct inet6_dev *idev;
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np;
struct in6_addr *saddr = NULL; struct in6_addr *saddr = NULL;
struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw; struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
struct icmp6hdr tmp_hdr; struct icmp6hdr tmp_hdr;
...@@ -454,6 +457,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb) ...@@ -454,6 +457,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (icmpv6_xmit_lock()) if (icmpv6_xmit_lock())
return; return;
sk = icmpv6_socket->sk;
np = inet6_sk(sk);
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif; fl.oif = np->mcast_oif;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment