diff options
author | Serhey Popovych <serhe.popovych@gmail.com> | 2017-06-20 06:29:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-20 15:34:02 -0400 |
commit | 07f615574f8ac499875b21c1142f26308234a92c (patch) | |
tree | 9b01c1d01c47a7a48ad18063217bb6ebd3fa68cb /net/ipv6/fib6_rules.c | |
parent | 7e113321eccba2b52c0e9d11129d370c9511e4db (diff) |
ipv6: Do not leak throw route references
While commit 73ba57bfae4a ("ipv6: fix backtracking for throw routes")
does good job on error propagation to the fib_rules_lookup()
in fib rules core framework that also corrects throw routes
handling, it does not solve route reference leakage problem
happened when we return -EAGAIN to the fib_rules_lookup()
and leave routing table entry referenced in arg->result.
If rule with matched throw route isn't last matched in the
list we overwrite arg->result losing reference on throw
route stored previously forever.
We also partially revert commit ab997ad40839 ("ipv6: fix the
incorrect return value of throw route") since we never return
routing table entry with dst.error == -EAGAIN when
CONFIG_IPV6_MULTIPLE_TABLES is on. Also there is no point
to check for RTF_REJECT flag since it is always set throw
route.
Fixes: 73ba57bfae4a ("ipv6: fix backtracking for throw routes")
Signed-off-by: Serhey Popovych <serhe.popovych@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/fib6_rules.c')
-rw-r--r-- | net/ipv6/fib6_rules.c | 22 |
1 files changed, 6 insertions, 16 deletions
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index eea23b57c6a5..ec849d88a662 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -32,7 +32,6 @@ struct fib6_rule { | |||
32 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, | 32 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, |
33 | int flags, pol_lookup_t lookup) | 33 | int flags, pol_lookup_t lookup) |
34 | { | 34 | { |
35 | struct rt6_info *rt; | ||
36 | struct fib_lookup_arg arg = { | 35 | struct fib_lookup_arg arg = { |
37 | .lookup_ptr = lookup, | 36 | .lookup_ptr = lookup, |
38 | .flags = FIB_LOOKUP_NOREF, | 37 | .flags = FIB_LOOKUP_NOREF, |
@@ -44,21 +43,11 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, | |||
44 | fib_rules_lookup(net->ipv6.fib6_rules_ops, | 43 | fib_rules_lookup(net->ipv6.fib6_rules_ops, |
45 | flowi6_to_flowi(fl6), flags, &arg); | 44 | flowi6_to_flowi(fl6), flags, &arg); |
46 | 45 | ||
47 | rt = arg.result; | 46 | if (arg.result) |
47 | return arg.result; | ||
48 | 48 | ||
49 | if (!rt) { | 49 | dst_hold(&net->ipv6.ip6_null_entry->dst); |
50 | dst_hold(&net->ipv6.ip6_null_entry->dst); | 50 | return &net->ipv6.ip6_null_entry->dst; |
51 | return &net->ipv6.ip6_null_entry->dst; | ||
52 | } | ||
53 | |||
54 | if (rt->rt6i_flags & RTF_REJECT && | ||
55 | rt->dst.error == -EAGAIN) { | ||
56 | ip6_rt_put(rt); | ||
57 | rt = net->ipv6.ip6_null_entry; | ||
58 | dst_hold(&rt->dst); | ||
59 | } | ||
60 | |||
61 | return &rt->dst; | ||
62 | } | 51 | } |
63 | 52 | ||
64 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | 53 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, |
@@ -121,7 +110,8 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
121 | flp6->saddr = saddr; | 110 | flp6->saddr = saddr; |
122 | } | 111 | } |
123 | err = rt->dst.error; | 112 | err = rt->dst.error; |
124 | goto out; | 113 | if (err != -EAGAIN) |
114 | goto out; | ||
125 | } | 115 | } |
126 | again: | 116 | again: |
127 | ip6_rt_put(rt); | 117 | ip6_rt_put(rt); |