Skip to content

Commit 48a3d04

Browse files
Phil Suttergregkh
authored andcommitted
netfilter: nf_tables: Introduce NFTA_DEVICE_PREFIX
[ Upstream commit 4039ce7 ] 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 <phil@nwl.cc> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 96040b2 commit 48a3d04

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
@@ -1953,6 +1953,18 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
19531953
return -ENOSPC;
19541954
}
19551955

1956+
static bool hook_is_prefix(struct nft_hook *hook)
1957+
{
1958+
return strlen(hook->ifname) >= hook->ifnamelen;
1959+
}
1960+
1961+
static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook)
1962+
{
1963+
int attr = hook_is_prefix(hook) ? NFTA_DEVICE_PREFIX : NFTA_DEVICE_NAME;
1964+
1965+
return nla_put_string(skb, attr, hook->ifname);
1966+
}
1967+
19561968
static int nft_dump_basechain_hook(struct sk_buff *skb,
19571969
const struct net *net, int family,
19581970
const struct nft_base_chain *basechain,
@@ -1984,16 +1996,15 @@ static int nft_dump_basechain_hook(struct sk_buff *skb,
19841996
if (!first)
19851997
first = hook;
19861998

1987-
if (nla_put(skb, NFTA_DEVICE_NAME,
1988-
hook->ifnamelen, hook->ifname))
1999+
if (nft_nla_put_hook_dev(skb, hook))
19892000
goto nla_put_failure;
19902001
n++;
19912002
}
19922003
nla_nest_end(skb, nest_devs);
19932004

19942005
if (n == 1 &&
1995-
nla_put(skb, NFTA_HOOK_DEV,
1996-
first->ifnamelen, first->ifname))
2006+
!hook_is_prefix(first) &&
2007+
nla_put_string(skb, NFTA_HOOK_DEV, first->ifname))
19972008
goto nla_put_failure;
19982009
}
19992010
nla_nest_end(skb, nest);
@@ -2297,7 +2308,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)
22972308
}
22982309

22992310
static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
2300-
const struct nlattr *attr)
2311+
const struct nlattr *attr,
2312+
bool prefix)
23012313
{
23022314
struct nf_hook_ops *ops;
23032315
struct net_device *dev;
@@ -2314,7 +2326,8 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
23142326
if (err < 0)
23152327
goto err_hook_free;
23162328

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

23192332
/* nf_tables_netdev_event() is called under rtnl_mutex, this is
23202333
* indirectly serializing all the other holders of the commit_mutex with
@@ -2361,14 +2374,22 @@ static int nf_tables_parse_netdev_hooks(struct net *net,
23612374
struct nft_hook *hook, *next;
23622375
const struct nlattr *tmp;
23632376
int rem, n = 0, err;
2377+
bool prefix;
23642378

23652379
nla_for_each_nested(tmp, attr, rem) {
2366-
if (nla_type(tmp) != NFTA_DEVICE_NAME) {
2380+
switch (nla_type(tmp)) {
2381+
case NFTA_DEVICE_NAME:
2382+
prefix = false;
2383+
break;
2384+
case NFTA_DEVICE_PREFIX:
2385+
prefix = true;
2386+
break;
2387+
default:
23672388
err = -EINVAL;
23682389
goto err_hook;
23692390
}
23702391

2371-
hook = nft_netdev_hook_alloc(net, tmp);
2392+
hook = nft_netdev_hook_alloc(net, tmp, prefix);
23722393
if (IS_ERR(hook)) {
23732394
NL_SET_BAD_ATTR(extack, tmp);
23742395
err = PTR_ERR(hook);
@@ -2414,7 +2435,7 @@ static int nft_chain_parse_netdev(struct net *net, struct nlattr *tb[],
24142435
int err;
24152436

24162437
if (tb[NFTA_HOOK_DEV]) {
2417-
hook = nft_netdev_hook_alloc(net, tb[NFTA_HOOK_DEV]);
2438+
hook = nft_netdev_hook_alloc(net, tb[NFTA_HOOK_DEV], false);
24182439
if (IS_ERR(hook)) {
24192440
NL_SET_BAD_ATTR(extack, tb[NFTA_HOOK_DEV]);
24202441
return PTR_ERR(hook);
@@ -9424,8 +9445,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
94249445

94259446
list_for_each_entry_rcu(hook, hook_list, list,
94269447
lockdep_commit_lock_is_held(net)) {
9427-
if (nla_put(skb, NFTA_DEVICE_NAME,
9428-
hook->ifnamelen, hook->ifname))
9448+
if (nft_nla_put_hook_dev(skb, hook))
94299449
goto nla_put_failure;
94309450
}
94319451
nla_nest_end(skb, nest_devs);

0 commit comments

Comments
 (0)