Commit 46b3a421903aa2a4bc9731ca4663cee3ea869dab
Committed by
David S. Miller
1 parent
378307217e
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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>
Showing 1 changed file with 11 additions and 3 deletions Side-by-side Diff
net/ipv6/fib6_rules.c
... | ... | @@ -55,26 +55,33 @@ |
55 | 55 | struct fib6_table *table; |
56 | 56 | struct net *net = rule->fr_net; |
57 | 57 | pol_lookup_t lookup = arg->lookup_ptr; |
58 | + int err = 0; | |
58 | 59 | |
59 | 60 | switch (rule->action) { |
60 | 61 | case FR_ACT_TO_TBL: |
61 | 62 | break; |
62 | 63 | case FR_ACT_UNREACHABLE: |
64 | + err = -ENETUNREACH; | |
63 | 65 | rt = net->ipv6.ip6_null_entry; |
64 | 66 | goto discard_pkt; |
65 | 67 | default: |
66 | 68 | case FR_ACT_BLACKHOLE: |
69 | + err = -EINVAL; | |
67 | 70 | rt = net->ipv6.ip6_blk_hole_entry; |
68 | 71 | goto discard_pkt; |
69 | 72 | case FR_ACT_PROHIBIT: |
73 | + err = -EACCES; | |
70 | 74 | rt = net->ipv6.ip6_prohibit_entry; |
71 | 75 | goto discard_pkt; |
72 | 76 | } |
73 | 77 | |
74 | 78 | table = fib6_get_table(net, rule->table); |
75 | - if (table) | |
76 | - rt = lookup(net, table, flp6, flags); | |
79 | + if (!table) { | |
80 | + err = -EAGAIN; | |
81 | + goto out; | |
82 | + } | |
77 | 83 | |
84 | + rt = lookup(net, table, flp6, flags); | |
78 | 85 | if (rt != net->ipv6.ip6_null_entry) { |
79 | 86 | struct fib6_rule *r = (struct fib6_rule *)rule; |
80 | 87 | |
... | ... | @@ -101,6 +108,7 @@ |
101 | 108 | } |
102 | 109 | again: |
103 | 110 | ip6_rt_put(rt); |
111 | + err = -EAGAIN; | |
104 | 112 | rt = NULL; |
105 | 113 | goto out; |
106 | 114 | |
... | ... | @@ -108,7 +116,7 @@ |
108 | 116 | dst_hold(&rt->dst); |
109 | 117 | out: |
110 | 118 | arg->result = rt; |
111 | - return rt == NULL ? -EAGAIN : 0; | |
119 | + return err; | |
112 | 120 | } |
113 | 121 | |
114 | 122 | static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) |