| From foo@baz Fri Nov 2 10:04:04 CET 2018 |
| From: Stefano Brivio <sbrivio@redhat.com> |
| Date: Wed, 24 Oct 2018 14:37:21 +0200 |
| Subject: ipv6/ndisc: Preserve IPv6 control buffer if protocol error handlers are called |
| |
| From: Stefano Brivio <sbrivio@redhat.com> |
| |
| [ Upstream commit ee1abcf689353f36d9322231b4320926096bdee0 ] |
| |
| Commit a61bbcf28a8c ("[NET]: Store skb->timestamp as offset to a base |
| timestamp") introduces a neighbour control buffer and zeroes it out in |
| ndisc_rcv(), as ndisc_recv_ns() uses it. |
| |
| Commit f2776ff04722 ("[IPV6]: Fix address/interface handling in UDP and |
| DCCP, according to the scoping architecture.") introduces the usage of the |
| IPv6 control buffer in protocol error handlers (e.g. inet6_iif() in |
| present-day __udp6_lib_err()). |
| |
| Now, with commit b94f1c0904da ("ipv6: Use icmpv6_notify() to propagate |
| redirect, instead of rt6_redirect()."), we call protocol error handlers |
| from ndisc_redirect_rcv(), after the control buffer is already stolen and |
| some parts are already zeroed out. This implies that inet6_iif() on this |
| path will always return zero. |
| |
| This gives unexpected results on UDP socket lookup in __udp6_lib_err(), as |
| we might actually need to match sockets for a given interface. |
| |
| Instead of always claiming the control buffer in ndisc_rcv(), do that only |
| when needed. |
| |
| Fixes: b94f1c0904da ("ipv6: Use icmpv6_notify() to propagate redirect, instead of rt6_redirect().") |
| Signed-off-by: Stefano Brivio <sbrivio@redhat.com> |
| Reviewed-by: Sabrina Dubroca <sd@queasysnail.net> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv6/ndisc.c | 3 +-- |
| 1 file changed, 1 insertion(+), 2 deletions(-) |
| |
| --- a/net/ipv6/ndisc.c |
| +++ b/net/ipv6/ndisc.c |
| @@ -1692,10 +1692,9 @@ int ndisc_rcv(struct sk_buff *skb) |
| return 0; |
| } |
| |
| - memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); |
| - |
| switch (msg->icmph.icmp6_type) { |
| case NDISC_NEIGHBOUR_SOLICITATION: |
| + memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); |
| ndisc_recv_ns(skb); |
| break; |
| |