[NET]: Fix fib_rules compatibility breakage

Based upon a patch from Patrick McHardy.

The fib_rules netlink attribute policy introduced in 2.6.19 broke
userspace compatibilty. When specifying a rule with "from all"
or "to all", iproute adds a zero byte long netlink attribute,
but the policy requires all addresses to have a size equal to
sizeof(struct in_addr)/sizeof(struct in6_addr), resulting in a
validation error.

Check attribute length of FRA_SRC/FRA_DST in the generic framework
by letting the family specific rules implementation provide the
length of an address. Report an error if address length is non
zero but no address attribute is provided. Fix actual bug by
checking address length for non-zero instead of relying on
availability of attribute.

Signed-off-by: Thomas Graf <[email protected]>
Signed-off-by: Patrick McHardy <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
Thomas Graf 2007-03-24 12:46:02 -07:00 • committed by David S. Miller
commit e1701c68c1
5 changed files with 48 additions and 24 deletions

View file

@ -171,8 +171,6 @@ static struct fib_table *fib_empty_table(void)
static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = {
FRA_GENERIC_POLICY,
[FRA_SRC] = { .type = NLA_U32 },
[FRA_DST] = { .type = NLA_U32 },
[FRA_FLOW] = { .type = NLA_U32 },
};
@ -183,8 +181,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
int err = -EINVAL;
struct fib4_rule *rule4 = (struct fib4_rule *) rule;
if (frh->src_len > 32 || frh->dst_len > 32 ||
(frh->tos & ~IPTOS_TOS_MASK))
if (frh->tos & ~IPTOS_TOS_MASK)
goto errout;
if (rule->table == RT_TABLE_UNSPEC) {
@ -201,10 +198,10 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
}
}
if (tb[FRA_SRC])
if (frh->src_len)
rule4->src = nla_get_be32(tb[FRA_SRC]);
if (tb[FRA_DST])
if (frh->dst_len)
rule4->dst = nla_get_be32(tb[FRA_DST]);
#ifdef CONFIG_NET_CLS_ROUTE
@ -242,10 +239,10 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
return 0;
#endif
if (tb[FRA_SRC] && (rule4->src != nla_get_be32(tb[FRA_SRC])))
if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC])))
return 0;
if (tb[FRA_DST] && (rule4->dst != nla_get_be32(tb[FRA_DST])))
if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST])))
return 0;
return 1;
@ -309,6 +306,7 @@ static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
static struct fib_rules_ops fib4_rules_ops = {
.family = AF_INET,
.rule_size = sizeof(struct fib4_rule),
.addr_size = sizeof(u32),
.action = fib4_rule_action,
.match = fib4_rule_match,
.configure = fib4_rule_configure,