diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-08-01 02:54:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-01 03:26:22 -0400 |
commit | 46b3a421903aa2a4bc9731ca4663cee3ea869dab (patch) | |
tree | 79fe45a2dcc4055edddf87069ce278f3ce78176f /net/ipv6 | |
parent | 378307217ed9c318212ec3050d38d0e34b77604c (diff) |
ipv6: fib6_rules should return exact return value
With the addition of the suppress operation
(7764a45a8f1fe74d4f7d301eaca2e558e7e2831a ("fib_rules: add .suppress
operation") we rely on accurate error reporting of the fib_rules.actions.
fib6_rule_action always returned -EAGAIN in case we could not find a
matching route and 0 if a rule was matched. This also included a match
for blackhole or prohibited rule actions which could get suppressed by
the new logic.
So adapt fib6_rule_action to always return the correct error code as
its counterpart fib4_rule_action does. This also fixes a possiblity of
nullptr-deref where we don't find a table, thus rt == NULL. Because
the condition rt != ip6_null_entry still holdes it seems we could later
get a nullptr bug on dereference rt->dst.
v2:
a) Fixed a brain fart in the commit msg (the rule => a table, etc). No
changes to the patch.
Cc: Stefan Tomanek <stefan.tomanek@wertarbyte.de>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/fib6_rules.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index e64e6a55fc4a..554a4fbabfb3 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -55,26 +55,33 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
55 | struct fib6_table *table; | 55 | struct fib6_table *table; |
56 | struct net *net = rule->fr_net; | 56 | struct net *net = rule->fr_net; |
57 | pol_lookup_t lookup = arg->lookup_ptr; | 57 | pol_lookup_t lookup = arg->lookup_ptr; |
58 | int err = 0; | ||
58 | 59 | ||
59 | switch (rule->action) { | 60 | switch (rule->action) { |
60 | case FR_ACT_TO_TBL: | 61 | case FR_ACT_TO_TBL: |
61 | break; | 62 | break; |
62 | case FR_ACT_UNREACHABLE: | 63 | case FR_ACT_UNREACHABLE: |
64 | err = -ENETUNREACH; | ||
63 | rt = net->ipv6.ip6_null_entry; | 65 | rt = net->ipv6.ip6_null_entry; |
64 | goto discard_pkt; | 66 | goto discard_pkt; |
65 | default: | 67 | default: |
66 | case FR_ACT_BLACKHOLE: | 68 | case FR_ACT_BLACKHOLE: |
69 | err = -EINVAL; | ||
67 | rt = net->ipv6.ip6_blk_hole_entry; | 70 | rt = net->ipv6.ip6_blk_hole_entry; |
68 | goto discard_pkt; | 71 | goto discard_pkt; |
69 | case FR_ACT_PROHIBIT: | 72 | case FR_ACT_PROHIBIT: |
73 | err = -EACCES; | ||
70 | rt = net->ipv6.ip6_prohibit_entry; | 74 | rt = net->ipv6.ip6_prohibit_entry; |
71 | goto discard_pkt; | 75 | goto discard_pkt; |
72 | } | 76 | } |
73 | 77 | ||
74 | table = fib6_get_table(net, rule->table); | 78 | table = fib6_get_table(net, rule->table); |
75 | if (table) | 79 | if (!table) { |
76 | rt = lookup(net, table, flp6, flags); | 80 | err = -EAGAIN; |
81 | goto out; | ||
82 | } | ||
77 | 83 | ||
84 | rt = lookup(net, table, flp6, flags); | ||
78 | if (rt != net->ipv6.ip6_null_entry) { | 85 | if (rt != net->ipv6.ip6_null_entry) { |
79 | struct fib6_rule *r = (struct fib6_rule *)rule; | 86 | struct fib6_rule *r = (struct fib6_rule *)rule; |
80 | 87 | ||
@@ -101,6 +108,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
101 | } | 108 | } |
102 | again: | 109 | again: |
103 | ip6_rt_put(rt); | 110 | ip6_rt_put(rt); |
111 | err = -EAGAIN; | ||
104 | rt = NULL; | 112 | rt = NULL; |
105 | goto out; | 113 | goto out; |
106 | 114 | ||
@@ -108,7 +116,7 @@ discard_pkt: | |||
108 | dst_hold(&rt->dst); | 116 | dst_hold(&rt->dst); |
109 | out: | 117 | out: |
110 | arg->result = rt; | 118 | arg->result = rt; |
111 | return rt == NULL ? -EAGAIN : 0; | 119 | return err; |
112 | } | 120 | } |
113 | 121 | ||
114 | static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) | 122 | static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) |