On Fri, Sep 27, 2013 at 01:53:14PM -0400, Nicolas HICHER wrote:
[...]
> On debian wheezy, jessie, sid, if you try to delete an inexistant
> table with ip rule, the local table will be deleted. The table number must
> be greater than 256: 

There are two different code-paths for table id < 256 and above or equal.
For the "above or equal to 256" path, the table id is attached as a
netlink attribute instead of using the (8bit) table field.
When the netlink attribute is used, the table field is set to RT_TABLE_UNSPEC
which is defined as 0.

There's a helper function to handle getting the correct table id
in include/net/fib_rules.h called "frh_get_table", see:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/net/fib_rules.h#n111

It looks like for the delete rule case, this is called from the
"list_for_each" loop in "fib_nl_delrule" in file net/core/fib_rules.c, see:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/net/core/fib_rules.c#n464
If I understand the code correctly, the loop is trying to locate the correct
rule based on the matching criterias (skipping any criteria which is not set).
The precondition to check if specified table id and rule table id matches
seems to be buggy though:
"               if (frh->table && (frh_get_table(frh, tb) != rule->table))"

When iproute2 is using the netlink attribute I think frh->table will be
RT_TABLE_UNSPEC, which means 0. So the matching is not performed
and (given that all other criterias match) the first rule (local) will
be deleted.

Would be very welcome if you could rebuild the kernel with the attached patch
and report back if it solves the problem for you or not.

-- 
Andreas Henriksson
>From b65e3e7512cffb75da9ec1d78898eab80ad3d493 Mon Sep 17 00:00:00 2001
From: Andreas Henriksson <andr...@fatal.se>
Date: Thu, 7 Nov 2013 13:50:43 +0100
Subject: [PATCH] Fix "ip rule delete table 256"

When trying to delete a table >= 256 using iproute2 the local table
will be deleted.
The table id is specified as a netlink attribute when it needs more then
8 bits and iproute2 then sets the table field to RT_TABLE_UNSPEC (0).
Preconditions to matching the table id in the rule delete code
doesn't seem to take the "table id in netlink attribute" into condition
so the frh_get_table helper function never gets to do its job when
matching against current rule.

Originally reported at: http://bugs.debian.org/724783

Reported-by: Nicolas HICHER <nhic...@avencall.com>
Signed-off-by: Andreas Henriksson <andr...@fatal.se>
---
 net/core/fib_rules.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 2e65413..2efb6bf 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -460,7 +460,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
 		if (frh->action && (frh->action != rule->action))
 			continue;
 
-		if (frh->table && (frh_get_table(frh, tb) != rule->table))
+		if (frh_get_table(frh, tb) && (frh_get_table(frh, tb) != rule->table))
 			continue;
 
 		if (tb[FRA_PRIORITY] &&
-- 
1.8.4.2

Reply via email to