Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: use NLA_POLICY_MASK to test for valid flag options

nf_tables relies on manual test of netlink attributes coming from userspace
even in cases where this could be handled via netlink policy.

Convert a bunch of 'flag' attributes to use NLA_POLICY_MASK checks.

Signed-off-by: Florian Westphal <fw@strlen.de>

+20 -27
+9 -8
net/netfilter/nft_fib.c
··· 14 14 #include <net/netfilter/nf_tables.h> 15 15 #include <net/netfilter/nft_fib.h> 16 16 17 - const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = { 18 - [NFTA_FIB_DREG] = { .type = NLA_U32 }, 19 - [NFTA_FIB_RESULT] = { .type = NLA_U32 }, 20 - [NFTA_FIB_FLAGS] = { .type = NLA_U32 }, 21 - }; 22 - EXPORT_SYMBOL(nft_fib_policy); 23 - 24 17 #define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \ 25 18 NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF | \ 26 19 NFTA_FIB_F_PRESENT) 20 + 21 + const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = { 22 + [NFTA_FIB_DREG] = { .type = NLA_U32 }, 23 + [NFTA_FIB_RESULT] = { .type = NLA_U32 }, 24 + [NFTA_FIB_FLAGS] = 25 + NLA_POLICY_MASK(NLA_BE32, NFTA_FIB_F_ALL), 26 + }; 27 + EXPORT_SYMBOL(nft_fib_policy); 27 28 28 29 int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, 29 30 const struct nft_data **data) ··· 78 77 79 78 priv->flags = ntohl(nla_get_be32(tb[NFTA_FIB_FLAGS])); 80 79 81 - if (priv->flags == 0 || (priv->flags & ~NFTA_FIB_F_ALL)) 80 + if (priv->flags == 0) 82 81 return -EINVAL; 83 82 84 83 if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) ==
+2 -4
net/netfilter/nft_lookup.c
··· 90 90 [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, 91 91 [NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, 92 92 [NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, 93 - [NFTA_LOOKUP_FLAGS] = { .type = NLA_U32 }, 93 + [NFTA_LOOKUP_FLAGS] = 94 + NLA_POLICY_MASK(NLA_BE32, NFT_LOOKUP_F_INV), 94 95 }; 95 96 96 97 static int nft_lookup_init(const struct nft_ctx *ctx, ··· 120 119 121 120 if (tb[NFTA_LOOKUP_FLAGS]) { 122 121 flags = ntohl(nla_get_be32(tb[NFTA_LOOKUP_FLAGS])); 123 - 124 - if (flags & ~NFT_LOOKUP_F_INV) 125 - return -EINVAL; 126 122 127 123 if (flags & NFT_LOOKUP_F_INV) 128 124 priv->invert = true;
+3 -5
net/netfilter/nft_masq.c
··· 20 20 }; 21 21 22 22 static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { 23 - [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, 23 + [NFTA_MASQ_FLAGS] = 24 + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), 24 25 [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, 25 26 [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, 26 27 }; ··· 48 47 struct nft_masq *priv = nft_expr_priv(expr); 49 48 int err; 50 49 51 - if (tb[NFTA_MASQ_FLAGS]) { 50 + if (tb[NFTA_MASQ_FLAGS]) 52 51 priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); 53 - if (priv->flags & ~NF_NAT_RANGE_MASK) 54 - return -EINVAL; 55 - } 56 52 57 53 if (tb[NFTA_MASQ_REG_PROTO_MIN]) { 58 54 err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN],
+3 -5
net/netfilter/nft_nat.c
··· 132 132 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 }, 133 133 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 }, 134 134 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 }, 135 - [NFTA_NAT_FLAGS] = { .type = NLA_U32 }, 135 + [NFTA_NAT_FLAGS] = 136 + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), 136 137 }; 137 138 138 139 static int nft_nat_validate(const struct nft_ctx *ctx, ··· 247 246 priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 248 247 } 249 248 250 - if (tb[NFTA_NAT_FLAGS]) { 249 + if (tb[NFTA_NAT_FLAGS]) 251 250 priv->flags |= ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); 252 - if (priv->flags & ~NF_NAT_RANGE_MASK) 253 - return -EOPNOTSUPP; 254 - } 255 251 256 252 return nf_ct_netns_get(ctx->net, family); 257 253 }
+3 -5
net/netfilter/nft_redir.c
··· 22 22 static const struct nla_policy nft_redir_policy[NFTA_REDIR_MAX + 1] = { 23 23 [NFTA_REDIR_REG_PROTO_MIN] = { .type = NLA_U32 }, 24 24 [NFTA_REDIR_REG_PROTO_MAX] = { .type = NLA_U32 }, 25 - [NFTA_REDIR_FLAGS] = { .type = NLA_U32 }, 25 + [NFTA_REDIR_FLAGS] = 26 + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), 26 27 }; 27 28 28 29 static int nft_redir_validate(const struct nft_ctx *ctx, ··· 69 68 priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 70 69 } 71 70 72 - if (tb[NFTA_REDIR_FLAGS]) { 71 + if (tb[NFTA_REDIR_FLAGS]) 73 72 priv->flags = ntohl(nla_get_be32(tb[NFTA_REDIR_FLAGS])); 74 - if (priv->flags & ~NF_NAT_RANGE_MASK) 75 - return -EINVAL; 76 - } 77 73 78 74 return nf_ct_netns_get(ctx->net, ctx->family); 79 75 }