ipv6: Initialize rt6_info properly in ip6_blackhole_route()
ip6_blackhole_route() does not initialize the newly allocated
rt6_info properly. This patch:
1. Call rt6_info_init() to initialize rt6i_siblings and rt6i_uncached
2. The current rt->dst._metrics init code is incorrect:
- 'rt->dst._metrics = ort->dst._metris' is not always safe
- Not sure what dst_copy_metrics() is trying to do here
considering ip6_rt_blackhole_cow_metrics() always returns
NULL
Fix:
- Always do dst_copy_metrics()
- Replace ip6_rt_blackhole_cow_metrics() with
dst_cow_metrics_generic()
3. Mask out the RTF_PCPU bit from the newly allocated blackhole route.
This bug triggers an oops (reported by Phil Sutter) in rt6_get_cookie().
It is because RTF_PCPU is set while rt->dst.from is NULL.
Fixes: d52d3997f8
("ipv6: Create percpu rt6_info")
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Reported-by: Phil Sutter <phil@nwl.cc>
Tested-by: Phil Sutter <phil@nwl.cc>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Cc: Julian Anastasov <ja@ssi.bg>
Cc: Phil Sutter <phil@nwl.cc>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ebfa45f0d9
commit
0a1f596200
|
@ -248,12 +248,6 @@ static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
|
|||
{
|
||||
}
|
||||
|
||||
static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
|
||||
unsigned long old)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dst_ops ip6_dst_blackhole_ops = {
|
||||
.family = AF_INET6,
|
||||
.destroy = ip6_dst_destroy,
|
||||
|
@ -262,7 +256,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
|
|||
.default_advmss = ip6_default_advmss,
|
||||
.update_pmtu = ip6_rt_blackhole_update_pmtu,
|
||||
.redirect = ip6_rt_blackhole_redirect,
|
||||
.cow_metrics = ip6_rt_blackhole_cow_metrics,
|
||||
.cow_metrics = dst_cow_metrics_generic,
|
||||
.neigh_lookup = ip6_neigh_lookup,
|
||||
};
|
||||
|
||||
|
@ -1219,24 +1213,20 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
|
|||
|
||||
rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
|
||||
if (rt) {
|
||||
rt6_info_init(rt);
|
||||
|
||||
new = &rt->dst;
|
||||
|
||||
memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
|
||||
|
||||
new->__use = 1;
|
||||
new->input = dst_discard;
|
||||
new->output = dst_discard_sk;
|
||||
|
||||
if (dst_metrics_read_only(&ort->dst))
|
||||
new->_metrics = ort->dst._metrics;
|
||||
else
|
||||
dst_copy_metrics(new, &ort->dst);
|
||||
dst_copy_metrics(new, &ort->dst);
|
||||
rt->rt6i_idev = ort->rt6i_idev;
|
||||
if (rt->rt6i_idev)
|
||||
in6_dev_hold(rt->rt6i_idev);
|
||||
|
||||
rt->rt6i_gateway = ort->rt6i_gateway;
|
||||
rt->rt6i_flags = ort->rt6i_flags;
|
||||
rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
|
||||
rt->rt6i_metric = 0;
|
||||
|
||||
memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
|
||||
|
|
Loading…
Reference in New Issue