Skip to content

Commit

Permalink
netfilter: nftables: add set expression flags
Browse files Browse the repository at this point in the history
The set flag NFT_SET_EXPR provides a hint to the kernel that userspace
supports for multiple expressions per set element. In the same
direction, NFT_DYNSET_F_EXPR specifies that dynset expression defines
multiple expressions per set element.

This allows new userspace software with old kernels to bail out with
EOPNOTSUPP. This update is similar to ef516e8 ("netfilter:
nf_tables: reintroduce the NFT_SET_CONCAT flag"). The NFT_SET_EXPR flag
needs to be set on when the NFTA_SET_EXPRESSIONS attribute is specified.
The NFT_SET_EXPR flag is not set on with NFTA_SET_EXPR to retain
backward compatibility in old userspace binaries.

Fixes: 48b0ae0 ("netfilter: nftables: netlink support for several set element expressions")
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
ummakynes committed Dec 28, 2020
1 parent 95cd4bc commit b4e70d8
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 3 deletions.
3 changes: 3 additions & 0 deletions include/uapi/linux/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ enum nft_rule_compat_attributes {
* @NFT_SET_EVAL: set can be updated from the evaluation path
* @NFT_SET_OBJECT: set contains stateful objects
* @NFT_SET_CONCAT: set contains a concatenation
* @NFT_SET_EXPR: set contains expressions
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
Expand All @@ -303,6 +304,7 @@ enum nft_set_flags {
NFT_SET_EVAL = 0x20,
NFT_SET_OBJECT = 0x40,
NFT_SET_CONCAT = 0x80,
NFT_SET_EXPR = 0x100,
};

/**
Expand Down Expand Up @@ -706,6 +708,7 @@ enum nft_dynset_ops {

enum nft_dynset_flags {
NFT_DYNSET_F_INV = (1 << 0),
NFT_DYNSET_F_EXPR = (1 << 1),
};

/**
Expand Down
6 changes: 5 additions & 1 deletion net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -4162,7 +4162,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT))
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
Expand Down Expand Up @@ -4304,6 +4304,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
struct nlattr *tmp;
int left;

if (!(flags & NFT_SET_EXPR)) {
err = -EINVAL;
goto err_set_alloc_name;
}
i = 0;
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
if (i == NFT_SET_EXPR_MAX) {
Expand Down
9 changes: 7 additions & 2 deletions net/netfilter/nft_dynset.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct nft_dynset {
enum nft_registers sreg_key:8;
enum nft_registers sreg_data:8;
bool invert;
bool expr;
u8 num_exprs;
u64 timeout;
struct nft_expr *expr_array[NFT_SET_EXPR_MAX];
Expand Down Expand Up @@ -175,11 +176,12 @@ static int nft_dynset_init(const struct nft_ctx *ctx,

if (tb[NFTA_DYNSET_FLAGS]) {
u32 flags = ntohl(nla_get_be32(tb[NFTA_DYNSET_FLAGS]));

if (flags & ~NFT_DYNSET_F_INV)
if (flags & ~(NFT_DYNSET_F_INV | NFT_DYNSET_F_EXPR))
return -EOPNOTSUPP;
if (flags & NFT_DYNSET_F_INV)
priv->invert = true;
if (flags & NFT_DYNSET_F_EXPR)
priv->expr = true;
}

set = nft_set_lookup_global(ctx->net, ctx->table,
Expand Down Expand Up @@ -261,6 +263,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
struct nlattr *tmp;
int left;

if (!priv->expr)
return -EINVAL;

i = 0;
nla_for_each_nested(tmp, tb[NFTA_DYNSET_EXPRESSIONS], left) {
if (i == NFT_SET_EXPR_MAX) {
Expand Down

0 comments on commit b4e70d8

Please sign in to comment.