Some bitwise operations are generated in user space when munging paylod expressions. During delinearization, user space attempts to eliminate these operations. However, it does this before deducing the byte-order or the correct length in bits of the operands, which means that it doesn't always handle multi-byte host-endian operations correctly. Therefore, add support for storing the bit-length of the expression, even though the kernel doesn't use it, in order to be able to pass it back to user space. Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nft_bitwise.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 466fd3f4447c..f3dcc4a34ff1 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -561,6 +561,7 @@ enum nft_bitwise_ops { * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) * @NFTA_BITWISE_DATA: argument for non-boolean operations * (NLA_NESTED: nft_data_attributes) + * @NFTA_BITWISE_NBITS: length of operation in bits (NLA_U32) * * The bitwise expression supports boolean and shift operations. It implements * the boolean operations by performing the following operation: @@ -584,6 +585,7 @@ enum nft_bitwise_attributes { NFTA_BITWISE_XOR, NFTA_BITWISE_OP, NFTA_BITWISE_DATA, + NFTA_BITWISE_NBITS, __NFTA_BITWISE_MAX }; #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c index 83590afe3768..a120eaadb3e7 100644 --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c @@ -23,6 +23,7 @@ struct nft_bitwise { struct nft_data mask; struct nft_data xor; struct nft_data data; + u16 nbits; }; static void nft_bitwise_eval_bool(u32 *dst, const u32 *src, @@ -88,6 +89,7 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { [NFTA_BITWISE_XOR] = { .type = NLA_NESTED }, [NFTA_BITWISE_OP] = { .type = NLA_U32 }, [NFTA_BITWISE_DATA] = { .type = NLA_NESTED }, + [NFTA_BITWISE_NBITS] = { .type = NLA_U32 }, }; static int nft_bitwise_init_bool(struct nft_bitwise *priv, @@ -194,6 +196,16 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, } else { priv->op = NFT_BITWISE_BOOL; } + if (tb[NFTA_BITWISE_NBITS]) { + u32 nbits; + + err = nft_parse_u32_check(tb[NFTA_BITWISE_NBITS], + U8_MAX * BITS_PER_BYTE, &nbits); + if (err < 0) + return err; + + priv->nbits = nbits; + } switch(priv->op) { case NFT_BITWISE_BOOL: @@ -244,6 +256,8 @@ static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr) return -1; if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(priv->op))) return -1; + if (nla_put_be32(skb, NFTA_BITWISE_NBITS, htonl(priv->nbits))) + return -1; switch (priv->op) { case NFT_BITWISE_BOOL: -- 2.35.1