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

netfilter: nft_payload: extend offset to 65535 bytes

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>

authored by

Fernando Fernandez Mancera and committed by
Florian Westphal
077dc4a2 f4f9e059

+12 -8
+1 -1
include/net/netfilter/nf_tables_core.h
··· 73 73 74 74 struct nft_payload { 75 75 enum nft_payload_bases base:8; 76 - u8 offset; 76 + u16 offset; 77 77 u8 len; 78 78 u8 dreg; 79 79 };
+11 -7
net/netfilter/nft_payload.c
··· 40 40 41 41 /* add vlan header into the user buffer for if tag was removed by offloads */ 42 42 static bool 43 - nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len) 43 + nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u16 offset, u8 len) 44 44 { 45 45 int mac_off = skb_mac_header(skb) - skb->data; 46 46 u8 *vlanh, *dst_u8 = (u8 *) d; ··· 212 212 [NFTA_PAYLOAD_SREG] = { .type = NLA_U32 }, 213 213 [NFTA_PAYLOAD_DREG] = { .type = NLA_U32 }, 214 214 [NFTA_PAYLOAD_BASE] = { .type = NLA_U32 }, 215 - [NFTA_PAYLOAD_OFFSET] = NLA_POLICY_MAX(NLA_BE32, 255), 215 + [NFTA_PAYLOAD_OFFSET] = { .type = NLA_BE32 }, 216 216 [NFTA_PAYLOAD_LEN] = NLA_POLICY_MAX(NLA_BE32, 255), 217 217 [NFTA_PAYLOAD_CSUM_TYPE] = { .type = NLA_U32 }, 218 218 [NFTA_PAYLOAD_CSUM_OFFSET] = NLA_POLICY_MAX(NLA_BE32, 255), ··· 797 797 798 798 struct nft_payload_set { 799 799 enum nft_payload_bases base:8; 800 - u8 offset; 800 + u16 offset; 801 801 u8 len; 802 802 u8 sreg; 803 803 u8 csum_type; ··· 812 812 }; 813 813 814 814 static bool 815 - nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u8 offset, u8 len, 815 + nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len, 816 816 int *vlan_hlen) 817 817 { 818 818 struct nft_payload_vlan_hdr *vlanh; ··· 940 940 const struct nft_expr *expr, 941 941 const struct nlattr * const tb[]) 942 942 { 943 + u32 csum_offset, offset, csum_type = NFT_PAYLOAD_CSUM_NONE; 943 944 struct nft_payload_set *priv = nft_expr_priv(expr); 944 - u32 csum_offset, csum_type = NFT_PAYLOAD_CSUM_NONE; 945 945 int err; 946 946 947 947 priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE])); 948 - priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET])); 949 948 priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); 949 + 950 + err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U16_MAX, &offset); 951 + if (err < 0) 952 + return err; 953 + priv->offset = offset; 950 954 951 955 if (tb[NFTA_PAYLOAD_CSUM_TYPE]) 952 956 csum_type = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE])); ··· 1073 1069 if (tb[NFTA_PAYLOAD_DREG] == NULL) 1074 1070 return ERR_PTR(-EINVAL); 1075 1071 1076 - err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U8_MAX, &offset); 1072 + err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U16_MAX, &offset); 1077 1073 if (err < 0) 1078 1074 return ERR_PTR(err); 1079 1075