History

netfilter: nftables: add set expression flags

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 ef516e8625dd ("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.

Pablo Neira Ayuso committed 5 years ago

Commit b4e70d81 parent 95cd4bc3 files · +15 −3Browse files

Unified · Split

3 files
  1. include/uapi/linux/netfilter/nf_tables.h +3 −0
  2. net/netfilter/nf_tables_api.c +5 −1
  3. net/netfilter/nft_dynset.c +7 −2
include/uapi/linux/netfilter/nf_tables.h+3−0
@@ -293,6 +293,7 @@ enum nft_rule_compat_attributes { · 292 unmodified lines
293 * @NFT_SET_EVAL: set can be updated from the evaluation path293 * @NFT_SET_EVAL: set can be updated from the evaluation path
294 * @NFT_SET_OBJECT: set contains stateful objects294 * @NFT_SET_OBJECT: set contains stateful objects
295 * @NFT_SET_CONCAT: set contains a concatenation295 * @NFT_SET_CONCAT: set contains a concatenation
296 * @NFT_SET_EXPR: set contains expressions
296 */297 */
297enum nft_set_flags {298enum nft_set_flags {
298 NFT_SET_ANONYMOUS = 0x1,299 NFT_SET_ANONYMOUS = 0x1,
@@ -303,6 +304,7 @@ enum nft_set_flags { · 4 unmodified lines
303 NFT_SET_EVAL = 0x20,304 NFT_SET_EVAL = 0x20,
304 NFT_SET_OBJECT = 0x40,305 NFT_SET_OBJECT = 0x40,
305 NFT_SET_CONCAT = 0x80,306 NFT_SET_CONCAT = 0x80,
307 NFT_SET_EXPR = 0x100,
306};308};
307 309
308/**310/**
@@ -706,6 +708,7 @@ enum nft_dynset_ops { · 397 unmodified lines
706 708
707enum nft_dynset_flags {709enum nft_dynset_flags {
708 NFT_DYNSET_F_INV = (1 << 0),710 NFT_DYNSET_F_INV = (1 << 0),
711 NFT_DYNSET_F_EXPR = (1 << 1),
709};712};
710 713
711/**714/**
net/netfilter/nf_tables_api.c+5−1
@@ -4162,7 +4162,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, · 4161 unmodified lines
4162 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |4162 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
4163 NFT_SET_INTERVAL | NFT_SET_TIMEOUT |4163 NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
4164 NFT_SET_MAP | NFT_SET_EVAL |4164 NFT_SET_MAP | NFT_SET_EVAL |
4165 NFT_SET_OBJECT | NFT_SET_CONCAT))4165 NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
4166 return -EOPNOTSUPP;4166 return -EOPNOTSUPP;
4167 /* Only one of these operations is supported */4167 /* Only one of these operations is supported */
4168 if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==4168 if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
@@ -4304,6 +4304,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, · 135 unmodified lines
4304 struct nlattr *tmp;4304 struct nlattr *tmp;
4305 int left;4305 int left;
4306 4306
4307 if (!(flags & NFT_SET_EXPR)) {
4308 err = -EINVAL;
4309 goto err_set_alloc_name;
4310 }
4307 i = 0;4311 i = 0;
4308 nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {4312 nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
4309 if (i == NFT_SET_EXPR_MAX) {4313 if (i == NFT_SET_EXPR_MAX) {
net/netfilter/nft_dynset.c+7−2
@@ -19,6 +19,7 @@ struct nft_dynset { · 18 unmodified lines
19 enum nft_registers sreg_key:8;19 enum nft_registers sreg_key:8;
20 enum nft_registers sreg_data:8;20 enum nft_registers sreg_data:8;
21 bool invert;21 bool invert;
22 bool expr;
22 u8 num_exprs;23 u8 num_exprs;
23 u64 timeout;24 u64 timeout;
24 struct nft_expr *expr_array[NFT_SET_EXPR_MAX];25 struct nft_expr *expr_array[NFT_SET_EXPR_MAX];
@@ -175,11 +176,12 @@ static int nft_dynset_init(const struct nft_ctx *ctx, · 150 unmodified lines
175 176
176 if (tb[NFTA_DYNSET_FLAGS]) {177 if (tb[NFTA_DYNSET_FLAGS]) {
177 u32 flags = ntohl(nla_get_be32(tb[NFTA_DYNSET_FLAGS]));178 u32 flags = ntohl(nla_get_be32(tb[NFTA_DYNSET_FLAGS]));
178 179 if (flags & ~(NFT_DYNSET_F_INV | NFT_DYNSET_F_EXPR))
179 if (flags & ~NFT_DYNSET_F_INV)
180 return -EOPNOTSUPP;180 return -EOPNOTSUPP;
181 if (flags & NFT_DYNSET_F_INV)181 if (flags & NFT_DYNSET_F_INV)
182 priv->invert = true;182 priv->invert = true;
183 if (flags & NFT_DYNSET_F_EXPR)
184 priv->expr = true;
183 }185 }
184 186
185 set = nft_set_lookup_global(ctx->net, ctx->table,187 set = nft_set_lookup_global(ctx->net, ctx->table,
@@ -261,6 +263,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx, · 75 unmodified lines
261 struct nlattr *tmp;263 struct nlattr *tmp;
262 int left;264 int left;
263 265
266 if (!priv->expr)
267 return -EINVAL;
268
264 i = 0;269 i = 0;
265 nla_for_each_nested(tmp, tb[NFTA_DYNSET_EXPRESSIONS], left) {270 nla_for_each_nested(tmp, tb[NFTA_DYNSET_EXPRESSIONS], left) {
266 if (i == NFT_SET_EXPR_MAX) {271 if (i == NFT_SET_EXPR_MAX) {