Skip to content

Commit 4039ce7

Browse files
Phil SutterFlorian Westphal
authored andcommitted
netfilter: nf_tables: Introduce NFTA_DEVICE_PREFIX
This new attribute is supposed to be used instead of NFTA_DEVICE_NAME for simple wildcard interface specs. It holds a NUL-terminated string representing an interface name prefix to match on. While kernel code to distinguish full names from prefixes in NFTA_DEVICE_NAME is simpler than this solution, reusing the existing attribute with different semantics leads to confusion between different versions of kernel and user space though: * With old kernels, wildcards submitted by user space are accepted yet silently treated as regular names. * With old user space, wildcards submitted by kernel may cause crashes since libnftnl expects NUL-termination when there is none. Using a distinct attribute type sanitizes these situations as the receiving part detects and rejects the unexpected attribute nested in *_HOOK_DEVS attributes. Fixes: 6d07a28 ("netfilter: nf_tables: Support wildcard netdev hook specs") Signed-off-by: Phil Sutter <[email protected]> Signed-off-by: Florian Westphal <[email protected]>
1 parent 661a4f3 commit 4039ce7

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,10 +1784,12 @@ enum nft_synproxy_attributes {
17841784
* enum nft_device_attributes - nf_tables device netlink attributes
17851785
*
17861786
* @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
1787+
* @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING)
17871788
*/
17881789
enum nft_devices_attributes {
17891790
NFTA_DEVICE_UNSPEC,
17901791
NFTA_DEVICE_NAME,
1792+
NFTA_DEVICE_PREFIX,
17911793
__NFTA_DEVICE_MAX
17921794
};
17931795
#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)

net/netfilter/nf_tables_api.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,18 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
19591959
return -ENOSPC;
19601960
}
19611961

1962+
static bool hook_is_prefix(struct nft_hook *hook)
1963+
{
1964+
return strlen(hook->ifname) >= hook->ifnamelen;
1965+
}
1966+
1967+
static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook)
1968+
{
1969+
int attr = hook_is_prefix(hook) ? NFTA_DEVICE_PREFIX : NFTA_DEVICE_NAME;
1970+
1971+
return nla_put_string(skb, attr, hook->ifname);
1972+
}
1973+
19621974
static int nft_dump_basechain_hook(struct sk_buff *skb,
19631975
const struct net *net, int family,
19641976
const struct nft_base_chain *basechain,
@@ -1990,16 +2002,15 @@ static int nft_dump_basechain_hook(struct sk_buff *skb,
19902002
if (!first)
19912003
first = hook;
19922004

1993-
if (nla_put(skb, NFTA_DEVICE_NAME,
1994-
hook->ifnamelen, hook->ifname))
2005+
if (nft_nla_put_hook_dev(skb, hook))
19952006
goto nla_put_failure;
19962007
n++;
19972008
}
19982009
nla_nest_end(skb, nest_devs);
19992010

20002011
if (n == 1 &&
2001-
nla_put(skb, NFTA_HOOK_DEV,
2002-
first->ifnamelen, first->ifname))
2012+
!hook_is_prefix(first) &&
2013+
nla_put_string(skb, NFTA_HOOK_DEV, first->ifname))
20032014
goto nla_put_failure;
20042015
}
20052016
nla_nest_end(skb, nest);
@@ -2310,7 +2321,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)
23102321
}
23112322

23122323
static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
2313-
const struct nlattr *attr)
2324+
const struct nlattr *attr,
2325+
bool prefix)
23142326
{
23152327
struct nf_hook_ops *ops;
23162328
struct net_device *dev;
@@ -2327,7 +2339,8 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
23272339
if (err < 0)
23282340
goto err_hook_free;
23292341

2330-
hook->ifnamelen = nla_len(attr);
2342+
/* include the terminating NUL-char when comparing non-prefixes */
2343+
hook->ifnamelen = strlen(hook->ifname) + !prefix;
23312344

23322345
/* nf_tables_netdev_event() is called under rtnl_mutex, this is
23332346
* indirectly serializing all the other holders of the commit_mutex with
@@ -2374,14 +2387,22 @@ static int nf_tables_parse_netdev_hooks(struct net *net,
23742387
struct nft_hook *hook, *next;
23752388
const struct nlattr *tmp;
23762389
int rem, n = 0, err;
2390+
bool prefix;
23772391

23782392
nla_for_each_nested(tmp, attr, rem) {
2379-
if (nla_type(tmp) != NFTA_DEVICE_NAME) {
2393+
switch (nla_type(tmp)) {
2394+
case NFTA_DEVICE_NAME:
2395+
prefix = false;
2396+
break;
2397+
case NFTA_DEVICE_PREFIX:
2398+
prefix = true;
2399+
break;
2400+
default:
23802401
err = -EINVAL;
23812402
goto err_hook;
23822403
}
23832404

2384-
hook = nft_netdev_hook_alloc(net, tmp);
2405+
hook = nft_netdev_hook_alloc(net, tmp, prefix);
23852406
if (IS_ERR(hook)) {
23862407
NL_SET_BAD_ATTR(extack, tmp);
23872408
err = PTR_ERR(hook);
@@ -2427,7 +2448,7 @@ static int nft_chain_parse_netdev(struct net *net, struct nlattr *tb[],
24272448
int err;
24282449

24292450
if (tb[NFTA_HOOK_DEV]) {
2430-
hook = nft_netdev_hook_alloc(net, tb[NFTA_HOOK_DEV]);
2451+
hook = nft_netdev_hook_alloc(net, tb[NFTA_HOOK_DEV], false);
24312452
if (IS_ERR(hook)) {
24322453
NL_SET_BAD_ATTR(extack, tb[NFTA_HOOK_DEV]);
24332454
return PTR_ERR(hook);
@@ -9458,8 +9479,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
94589479

94599480
list_for_each_entry_rcu(hook, hook_list, list,
94609481
lockdep_commit_lock_is_held(net)) {
9461-
if (nla_put(skb, NFTA_DEVICE_NAME,
9462-
hook->ifnamelen, hook->ifname))
9482+
if (nft_nla_put_hook_dev(skb, hook))
94639483
goto nla_put_failure;
94649484
}
94659485
nla_nest_end(skb, nest_devs);

0 commit comments

Comments
 (0)