]> www.infradead.org Git - users/hch/misc.git/commitdiff
netfilter: nft_payload: extend offset to 65535 bytes
authorFernando Fernandez Mancera <fmancera@suse.de>
Thu, 28 Aug 2025 12:48:31 +0000 (14:48 +0200)
committerFlorian Westphal <fw@strlen.de>
Tue, 2 Sep 2025 13:28:18 +0000 (15:28 +0200)
In some situations 255 bytes offset is not enough to match or manipulate
the desired packet field. Increase the offset limit to 65535 or U16_MAX.

In addition, the nla policy maximum value is not set anymore as it is
limited to s16. Instead, the maximum value is checked during the payload
expression initialization function.

Tested with the nft command line tool.

table ip filter {
chain output {
@nh,2040,8 set 0xff
@nh,524280,8 set 0xff
@nh,524280,8 0xff
@nh,2040,8 0xff
}
}

Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
include/net/netfilter/nf_tables_core.h
net/netfilter/nft_payload.c

index 6c2f483d9828ddfcde6dee9612689f071e83384c..7644cfe9267d09e536eb5bbf666128ec349f9694 100644 (file)
@@ -73,7 +73,7 @@ struct nft_ct {
 
 struct nft_payload {
        enum nft_payload_bases  base:8;
-       u                     offset;
+       u16                     offset;
        u8                      len;
        u8                      dreg;
 };
index 059b28ffad0eb1248501f92243e81e2f2fd9a4f5..b0214418f75acd97f949b75f64382a76cc7fa865 100644 (file)
@@ -40,7 +40,7 @@ static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
 
 /* add vlan header into the user buffer for if tag was removed by offloads */
 static bool
-nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
+nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u16 offset, u8 len)
 {
        int mac_off = skb_mac_header(skb) - skb->data;
        u8 *vlanh, *dst_u8 = (u8 *) d;
@@ -212,7 +212,7 @@ static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
        [NFTA_PAYLOAD_SREG]             = { .type = NLA_U32 },
        [NFTA_PAYLOAD_DREG]             = { .type = NLA_U32 },
        [NFTA_PAYLOAD_BASE]             = { .type = NLA_U32 },
-       [NFTA_PAYLOAD_OFFSET]           = NLA_POLICY_MAX(NLA_BE32, 255),
+       [NFTA_PAYLOAD_OFFSET]           = { .type = NLA_BE32 },
        [NFTA_PAYLOAD_LEN]              = NLA_POLICY_MAX(NLA_BE32, 255),
        [NFTA_PAYLOAD_CSUM_TYPE]        = { .type = NLA_U32 },
        [NFTA_PAYLOAD_CSUM_OFFSET]      = NLA_POLICY_MAX(NLA_BE32, 255),
@@ -797,7 +797,7 @@ static int nft_payload_csum_inet(struct sk_buff *skb, const u32 *src,
 
 struct nft_payload_set {
        enum nft_payload_bases  base:8;
-       u                     offset;
+       u16                     offset;
        u8                      len;
        u8                      sreg;
        u8                      csum_type;
@@ -812,7 +812,7 @@ struct nft_payload_vlan_hdr {
 };
 
 static bool
-nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u8 offset, u8 len,
+nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len,
                     int *vlan_hlen)
 {
        struct nft_payload_vlan_hdr *vlanh;
@@ -940,14 +940,18 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
                                const struct nft_expr *expr,
                                const struct nlattr * const tb[])
 {
+       u32 csum_offset, offset, csum_type = NFT_PAYLOAD_CSUM_NONE;
        struct nft_payload_set *priv = nft_expr_priv(expr);
-       u32 csum_offset, csum_type = NFT_PAYLOAD_CSUM_NONE;
        int err;
 
        priv->base        = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
-       priv->offset      = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
        priv->len         = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
 
+       err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U16_MAX, &offset);
+       if (err < 0)
+               return err;
+       priv->offset = offset;
+
        if (tb[NFTA_PAYLOAD_CSUM_TYPE])
                csum_type = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
        if (tb[NFTA_PAYLOAD_CSUM_OFFSET]) {
@@ -1069,7 +1073,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
        if (tb[NFTA_PAYLOAD_DREG] == NULL)
                return ERR_PTR(-EINVAL);
 
-       err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U8_MAX, &offset);
+       err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U16_MAX, &offset);
        if (err < 0)
                return ERR_PTR(err);