aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2013-08-01 02:54:47 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-01 03:26:22 -0400
commit46b3a421903aa2a4bc9731ca4663cee3ea869dab (patch)
tree79fe45a2dcc4055edddf87069ce278f3ce78176f /net/ipv6
parent378307217ed9c318212ec3050d38d0e34b77604c (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.c14
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 }
102again: 109again:
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);
109out: 117out:
110 arg->result = rt; 118 arg->result = rt;
111 return rt == NULL ? -EAGAIN : 0; 119 return err;
112} 120}
113 121
114static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) 122static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)