diff options
author | Eric Dumazet <edumazet@google.com> | 2015-03-11 21:42:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-11 23:51:18 -0400 |
commit | c29390c6dfeee0944ac6b5610ebbe403944378fc (patch) | |
tree | befe951b043be948957abb1db65cee36dd7a379b | |
parent | c8a4d29988edb0db9ee80669f2e5e21bd9f7e0d0 (diff) |
xps: must clear sender_cpu before forwarding
John reported that my previous commit added a regression
on his router.
This is because sender_cpu & napi_id share a common location,
so get_xps_queue() can see garbage and perform an out of bound access.
We need to make sure sender_cpu is cleared before doing the transmit,
otherwise any NIC busy poll enabled (skb_mark_napi_id()) can trigger
this bug.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: John <jw@nuclearfallout.net>
Bisected-by: John <jw@nuclearfallout.net>
Fixes: 2bd82484bb4c ("xps: fix xps for stacked devices")
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/skbuff.h | 7 | ||||
-rw-r--r-- | net/core/skbuff.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_forward.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 1 |
4 files changed, 10 insertions, 1 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 30007afe70b3..f54d6659713a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -948,6 +948,13 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from) | |||
948 | to->l4_hash = from->l4_hash; | 948 | to->l4_hash = from->l4_hash; |
949 | }; | 949 | }; |
950 | 950 | ||
951 | static inline void skb_sender_cpu_clear(struct sk_buff *skb) | ||
952 | { | ||
953 | #ifdef CONFIG_XPS | ||
954 | skb->sender_cpu = 0; | ||
955 | #endif | ||
956 | } | ||
957 | |||
951 | #ifdef NET_SKBUFF_DATA_USES_OFFSET | 958 | #ifdef NET_SKBUFF_DATA_USES_OFFSET |
952 | static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) | 959 | static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) |
953 | { | 960 | { |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f80507823531..434e78e5254d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -4173,7 +4173,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet) | |||
4173 | skb->ignore_df = 0; | 4173 | skb->ignore_df = 0; |
4174 | skb_dst_drop(skb); | 4174 | skb_dst_drop(skb); |
4175 | skb->mark = 0; | 4175 | skb->mark = 0; |
4176 | skb->sender_cpu = 0; | 4176 | skb_sender_cpu_clear(skb); |
4177 | skb_init_secmark(skb); | 4177 | skb_init_secmark(skb); |
4178 | secpath_reset(skb); | 4178 | secpath_reset(skb); |
4179 | nf_reset(skb); | 4179 | nf_reset(skb); |
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 787b3c294ce6..d9bc28ac5d1b 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c | |||
@@ -67,6 +67,7 @@ static int ip_forward_finish(struct sk_buff *skb) | |||
67 | if (unlikely(opt->optlen)) | 67 | if (unlikely(opt->optlen)) |
68 | ip_forward_options(skb); | 68 | ip_forward_options(skb); |
69 | 69 | ||
70 | skb_sender_cpu_clear(skb); | ||
70 | return dst_output(skb); | 71 | return dst_output(skb); |
71 | } | 72 | } |
72 | 73 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0a04a37305d5..7e80b61b51ff 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -318,6 +318,7 @@ static int ip6_forward_proxy_check(struct sk_buff *skb) | |||
318 | 318 | ||
319 | static inline int ip6_forward_finish(struct sk_buff *skb) | 319 | static inline int ip6_forward_finish(struct sk_buff *skb) |
320 | { | 320 | { |
321 | skb_sender_cpu_clear(skb); | ||
321 | return dst_output(skb); | 322 | return dst_output(skb); |
322 | } | 323 | } |
323 | 324 | ||