Commit 46b3a421903aa2a4bc9731ca4663cee3ea869dab

Authored by Hannes Frederic Sowa
Committed by David S. Miller
1 parent 378307217e

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)