Commit a69a85da authored by wenxu's avatar wenxu Committed by Pablo Neira Ayuso

netfilter: nft_payload: fix missing check for matching length in offloads

Payload offload rule should also check the length of the match.
Moreover, check for unsupported link-layer fields:

 nft --debug=netlink add rule firewall zones vlan id 100
 ...
 [ payload load 2b @ link header + 0 => reg 1 ]

this loads 2byte base on ll header and offset 0.

This also fixes unsupported raw payload match.

Fixes: 92ad6325 ("netfilter: nf_tables: add hardware offload support")
Signed-off-by: default avatarwenxu <wenxu@ucloud.cn>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 085461c8
...@@ -161,13 +161,21 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx, ...@@ -161,13 +161,21 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
switch (priv->offset) { switch (priv->offset) {
case offsetof(struct ethhdr, h_source): case offsetof(struct ethhdr, h_source):
if (priv->len != ETH_ALEN)
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
src, ETH_ALEN, reg); src, ETH_ALEN, reg);
break; break;
case offsetof(struct ethhdr, h_dest): case offsetof(struct ethhdr, h_dest):
if (priv->len != ETH_ALEN)
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
dst, ETH_ALEN, reg); dst, ETH_ALEN, reg);
break; break;
default:
return -EOPNOTSUPP;
} }
return 0; return 0;
...@@ -181,14 +189,23 @@ static int nft_payload_offload_ip(struct nft_offload_ctx *ctx, ...@@ -181,14 +189,23 @@ static int nft_payload_offload_ip(struct nft_offload_ctx *ctx,
switch (priv->offset) { switch (priv->offset) {
case offsetof(struct iphdr, saddr): case offsetof(struct iphdr, saddr):
if (priv->len != sizeof(struct in_addr))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, src, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, src,
sizeof(struct in_addr), reg); sizeof(struct in_addr), reg);
break; break;
case offsetof(struct iphdr, daddr): case offsetof(struct iphdr, daddr):
if (priv->len != sizeof(struct in_addr))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, dst, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, dst,
sizeof(struct in_addr), reg); sizeof(struct in_addr), reg);
break; break;
case offsetof(struct iphdr, protocol): case offsetof(struct iphdr, protocol):
if (priv->len != sizeof(__u8))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
sizeof(__u8), reg); sizeof(__u8), reg);
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT); nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
...@@ -208,14 +225,23 @@ static int nft_payload_offload_ip6(struct nft_offload_ctx *ctx, ...@@ -208,14 +225,23 @@ static int nft_payload_offload_ip6(struct nft_offload_ctx *ctx,
switch (priv->offset) { switch (priv->offset) {
case offsetof(struct ipv6hdr, saddr): case offsetof(struct ipv6hdr, saddr):
if (priv->len != sizeof(struct in6_addr))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, src, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, src,
sizeof(struct in6_addr), reg); sizeof(struct in6_addr), reg);
break; break;
case offsetof(struct ipv6hdr, daddr): case offsetof(struct ipv6hdr, daddr):
if (priv->len != sizeof(struct in6_addr))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, dst, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, dst,
sizeof(struct in6_addr), reg); sizeof(struct in6_addr), reg);
break; break;
case offsetof(struct ipv6hdr, nexthdr): case offsetof(struct ipv6hdr, nexthdr):
if (priv->len != sizeof(__u8))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
sizeof(__u8), reg); sizeof(__u8), reg);
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT); nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
...@@ -255,10 +281,16 @@ static int nft_payload_offload_tcp(struct nft_offload_ctx *ctx, ...@@ -255,10 +281,16 @@ static int nft_payload_offload_tcp(struct nft_offload_ctx *ctx,
switch (priv->offset) { switch (priv->offset) {
case offsetof(struct tcphdr, source): case offsetof(struct tcphdr, source):
if (priv->len != sizeof(__be16))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src,
sizeof(__be16), reg); sizeof(__be16), reg);
break; break;
case offsetof(struct tcphdr, dest): case offsetof(struct tcphdr, dest):
if (priv->len != sizeof(__be16))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
sizeof(__be16), reg); sizeof(__be16), reg);
break; break;
...@@ -277,10 +309,16 @@ static int nft_payload_offload_udp(struct nft_offload_ctx *ctx, ...@@ -277,10 +309,16 @@ static int nft_payload_offload_udp(struct nft_offload_ctx *ctx,
switch (priv->offset) { switch (priv->offset) {
case offsetof(struct udphdr, source): case offsetof(struct udphdr, source):
if (priv->len != sizeof(__be16))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src,
sizeof(__be16), reg); sizeof(__be16), reg);
break; break;
case offsetof(struct udphdr, dest): case offsetof(struct udphdr, dest):
if (priv->len != sizeof(__be16))
return -EOPNOTSUPP;
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst, NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
sizeof(__be16), reg); sizeof(__be16), reg);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment