Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net 1) Fix insufficient validation of IPSET_ATTR_IPADDR_IPV6 reported by syzbot. 2) Remove spurious reports on nf_tables when lockdep gets disabled, from Florian Westphal. 3) Fix memleak in the error path of error path of ip_vs_control_net_init(), from Wang Hai. 4) Fix missing control data in flow dissector, otherwise IP address matching in hardware offload infra does not work. 5) Fix hardware offload match on prefix IP address when userspace does not send a bitwise expression to represent the prefix. * git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf: netfilter: nftables_offload: build mask based from the matching bytes netfilter: nftables_offload: set address type in control dissector ipvs: fix possible memory leak in ip_vs_control_net_init netfilter: nf_tables: avoid false-postive lockdep splat netfilter: ipset: prevent uninit-value in hash_ip6_add ==================== Link: https://lore.kernel.org/r/20201127190313.24947-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Коммит
bd2d5c54dc
|
@ -37,6 +37,7 @@ void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
|
|||
|
||||
struct nft_flow_key {
|
||||
struct flow_dissector_key_basic basic;
|
||||
struct flow_dissector_key_control control;
|
||||
union {
|
||||
struct flow_dissector_key_ipv4_addrs ipv4;
|
||||
struct flow_dissector_key_ipv6_addrs ipv6;
|
||||
|
@ -62,6 +63,9 @@ struct nft_flow_rule {
|
|||
|
||||
#define NFT_OFFLOAD_F_ACTION (1 << 0)
|
||||
|
||||
void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
|
||||
enum flow_dissector_key_id addr_type);
|
||||
|
||||
struct nft_rule;
|
||||
struct nft_flow_rule *nft_flow_rule_create(struct net *net, const struct nft_rule *rule);
|
||||
void nft_flow_rule_destroy(struct nft_flow_rule *flow);
|
||||
|
@ -74,6 +78,9 @@ int nft_flow_rule_offload_commit(struct net *net);
|
|||
offsetof(struct nft_flow_key, __base.__field); \
|
||||
(__reg)->len = __len; \
|
||||
(__reg)->key = __key; \
|
||||
|
||||
#define NFT_OFFLOAD_MATCH_EXACT(__key, __base, __field, __len, __reg) \
|
||||
NFT_OFFLOAD_MATCH(__key, __base, __field, __len, __reg) \
|
||||
memset(&(__reg)->mask, 0xff, (__reg)->len);
|
||||
|
||||
int nft_chain_offload_priority(struct nft_base_chain *basechain);
|
||||
|
|
|
@ -271,8 +271,7 @@ flag_nested(const struct nlattr *nla)
|
|||
|
||||
static const struct nla_policy ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] = {
|
||||
[IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct in6_addr) },
|
||||
[IPSET_ATTR_IPADDR_IPV6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
|
||||
};
|
||||
|
||||
int
|
||||
|
|
|
@ -4167,12 +4167,18 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
|
|||
|
||||
spin_lock_init(&ipvs->tot_stats.lock);
|
||||
|
||||
proc_create_net("ip_vs", 0, ipvs->net->proc_net, &ip_vs_info_seq_ops,
|
||||
sizeof(struct ip_vs_iter));
|
||||
proc_create_net_single("ip_vs_stats", 0, ipvs->net->proc_net,
|
||||
ip_vs_stats_show, NULL);
|
||||
proc_create_net_single("ip_vs_stats_percpu", 0, ipvs->net->proc_net,
|
||||
ip_vs_stats_percpu_show, NULL);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create_net("ip_vs", 0, ipvs->net->proc_net,
|
||||
&ip_vs_info_seq_ops, sizeof(struct ip_vs_iter)))
|
||||
goto err_vs;
|
||||
if (!proc_create_net_single("ip_vs_stats", 0, ipvs->net->proc_net,
|
||||
ip_vs_stats_show, NULL))
|
||||
goto err_stats;
|
||||
if (!proc_create_net_single("ip_vs_stats_percpu", 0,
|
||||
ipvs->net->proc_net,
|
||||
ip_vs_stats_percpu_show, NULL))
|
||||
goto err_percpu;
|
||||
#endif
|
||||
|
||||
if (ip_vs_control_net_init_sysctl(ipvs))
|
||||
goto err;
|
||||
|
@ -4180,6 +4186,17 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("ip_vs_stats_percpu", ipvs->net->proc_net);
|
||||
|
||||
err_percpu:
|
||||
remove_proc_entry("ip_vs_stats", ipvs->net->proc_net);
|
||||
|
||||
err_stats:
|
||||
remove_proc_entry("ip_vs", ipvs->net->proc_net);
|
||||
|
||||
err_vs:
|
||||
#endif
|
||||
free_percpu(ipvs->tot_stats.cpustats);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -4188,9 +4205,11 @@ void __net_exit ip_vs_control_net_cleanup(struct netns_ipvs *ipvs)
|
|||
{
|
||||
ip_vs_trash_cleanup(ipvs);
|
||||
ip_vs_control_net_cleanup_sysctl(ipvs);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("ip_vs_stats_percpu", ipvs->net->proc_net);
|
||||
remove_proc_entry("ip_vs_stats", ipvs->net->proc_net);
|
||||
remove_proc_entry("ip_vs", ipvs->net->proc_net);
|
||||
#endif
|
||||
free_percpu(ipvs->tot_stats.cpustats);
|
||||
}
|
||||
|
||||
|
|
|
@ -619,7 +619,8 @@ static int nft_request_module(struct net *net, const char *fmt, ...)
|
|||
static void lockdep_nfnl_nft_mutex_not_held(void)
|
||||
{
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
WARN_ON_ONCE(lockdep_nfnl_is_held(NFNL_SUBSYS_NFTABLES));
|
||||
if (debug_locks)
|
||||
WARN_ON_ONCE(lockdep_nfnl_is_held(NFNL_SUBSYS_NFTABLES));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,23 @@ static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
|
|||
return flow;
|
||||
}
|
||||
|
||||
void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
|
||||
enum flow_dissector_key_id addr_type)
|
||||
{
|
||||
struct nft_flow_match *match = &flow->match;
|
||||
struct nft_flow_key *mask = &match->mask;
|
||||
struct nft_flow_key *key = &match->key;
|
||||
|
||||
if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL))
|
||||
return;
|
||||
|
||||
key->control.addr_type = addr_type;
|
||||
mask->control.addr_type = 0xffff;
|
||||
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
|
||||
match->dissector.offset[FLOW_DISSECTOR_KEY_CONTROL] =
|
||||
offsetof(struct nft_flow_key, control);
|
||||
}
|
||||
|
||||
struct nft_flow_rule *nft_flow_rule_create(struct net *net,
|
||||
const struct nft_rule *rule)
|
||||
{
|
||||
|
|
|
@ -123,11 +123,11 @@ static int __nft_cmp_offload(struct nft_offload_ctx *ctx,
|
|||
u8 *mask = (u8 *)&flow->match.mask;
|
||||
u8 *key = (u8 *)&flow->match.key;
|
||||
|
||||
if (priv->op != NFT_CMP_EQ || reg->len != priv->len)
|
||||
if (priv->op != NFT_CMP_EQ || priv->len > reg->len)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(key + reg->offset, &priv->data, priv->len);
|
||||
memcpy(mask + reg->offset, ®->mask, priv->len);
|
||||
memcpy(key + reg->offset, &priv->data, reg->len);
|
||||
memcpy(mask + reg->offset, ®->mask, reg->len);
|
||||
|
||||
flow->match.dissector.used_keys |= BIT(reg->key);
|
||||
flow->match.dissector.offset[reg->key] = reg->base_offset;
|
||||
|
@ -137,7 +137,7 @@ static int __nft_cmp_offload(struct nft_offload_ctx *ctx,
|
|||
nft_reg_load16(priv->data.data) != ARPHRD_ETHER)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
nft_offload_update_dependency(ctx, &priv->data, priv->len);
|
||||
nft_offload_update_dependency(ctx, &priv->data, reg->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -724,22 +724,22 @@ static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
|
|||
|
||||
switch (priv->key) {
|
||||
case NFT_META_PROTOCOL:
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
|
||||
sizeof(__u16), reg);
|
||||
NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
|
||||
sizeof(__u16), reg);
|
||||
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
|
||||
break;
|
||||
case NFT_META_L4PROTO:
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
|
||||
sizeof(__u8), reg);
|
||||
NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
|
||||
sizeof(__u8), reg);
|
||||
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
|
||||
break;
|
||||
case NFT_META_IIF:
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_META, meta,
|
||||
ingress_ifindex, sizeof(__u32), reg);
|
||||
NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_META, meta,
|
||||
ingress_ifindex, sizeof(__u32), reg);
|
||||
break;
|
||||
case NFT_META_IIFTYPE:
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_META, meta,
|
||||
ingress_iftype, sizeof(__u16), reg);
|
||||
NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_META, meta,
|
||||
ingress_iftype, sizeof(__u16), reg);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
@ -165,6 +165,34 @@ nla_put_failure:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static bool nft_payload_offload_mask(struct nft_offload_reg *reg,
|
||||
u32 priv_len, u32 field_len)
|
||||
{
|
||||
unsigned int remainder, delta, k;
|
||||
struct nft_data mask = {};
|
||||
__be32 remainder_mask;
|
||||
|
||||
if (priv_len == field_len) {
|
||||
memset(®->mask, 0xff, priv_len);
|
||||
return true;
|
||||
} else if (priv_len > field_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&mask, 0xff, field_len);
|
||||
remainder = priv_len % sizeof(u32);
|
||||
if (remainder) {
|
||||
k = priv_len / sizeof(u32);
|
||||
delta = field_len - priv_len;
|
||||
remainder_mask = htonl(~((1 << (delta * BITS_PER_BYTE)) - 1));
|
||||
mask.data[k] = (__force u32)remainder_mask;
|
||||
}
|
||||
|
||||
memcpy(®->mask, &mask, field_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
|
||||
struct nft_flow_rule *flow,
|
||||
const struct nft_payload *priv)
|
||||
|
@ -173,21 +201,21 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
|
|||
|
||||
switch (priv->offset) {
|
||||
case offsetof(struct ethhdr, h_source):
|
||||
if (priv->len != ETH_ALEN)
|
||||
if (!nft_payload_offload_mask(reg, priv->len, ETH_ALEN))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
|
||||
src, ETH_ALEN, reg);
|
||||
break;
|
||||
case offsetof(struct ethhdr, h_dest):
|
||||
if (priv->len != ETH_ALEN)
|
||||
if (!nft_payload_offload_mask(reg, priv->len, ETH_ALEN))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
|
||||
dst, ETH_ALEN, reg);
|
||||
break;
|
||||
case offsetof(struct ethhdr, h_proto):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic,
|
||||
|
@ -195,14 +223,14 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
|
|||
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
|
||||
break;
|
||||
case offsetof(struct vlan_ethhdr, h_vlan_TCI):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_VLAN, vlan,
|
||||
vlan_tci, sizeof(__be16), reg);
|
||||
break;
|
||||
case offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_VLAN, vlan,
|
||||
|
@ -210,7 +238,7 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
|
|||
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
|
||||
break;
|
||||
case offsetof(struct vlan_ethhdr, h_vlan_TCI) + sizeof(struct vlan_hdr):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_CVLAN, vlan,
|
||||
|
@ -218,7 +246,7 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
|
|||
break;
|
||||
case offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto) +
|
||||
sizeof(struct vlan_hdr):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_CVLAN, vlan,
|
||||
|
@ -239,21 +267,25 @@ static int nft_payload_offload_ip(struct nft_offload_ctx *ctx,
|
|||
|
||||
switch (priv->offset) {
|
||||
case offsetof(struct iphdr, saddr):
|
||||
if (priv->len != sizeof(struct in_addr))
|
||||
if (!nft_payload_offload_mask(reg, priv->len,
|
||||
sizeof(struct in_addr)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, src,
|
||||
sizeof(struct in_addr), reg);
|
||||
nft_flow_rule_set_addr_type(flow, FLOW_DISSECTOR_KEY_IPV4_ADDRS);
|
||||
break;
|
||||
case offsetof(struct iphdr, daddr):
|
||||
if (priv->len != sizeof(struct in_addr))
|
||||
if (!nft_payload_offload_mask(reg, priv->len,
|
||||
sizeof(struct in_addr)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, dst,
|
||||
sizeof(struct in_addr), reg);
|
||||
nft_flow_rule_set_addr_type(flow, FLOW_DISSECTOR_KEY_IPV4_ADDRS);
|
||||
break;
|
||||
case offsetof(struct iphdr, protocol):
|
||||
if (priv->len != sizeof(__u8))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__u8)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
|
||||
|
@ -275,21 +307,25 @@ static int nft_payload_offload_ip6(struct nft_offload_ctx *ctx,
|
|||
|
||||
switch (priv->offset) {
|
||||
case offsetof(struct ipv6hdr, saddr):
|
||||
if (priv->len != sizeof(struct in6_addr))
|
||||
if (!nft_payload_offload_mask(reg, priv->len,
|
||||
sizeof(struct in6_addr)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, src,
|
||||
sizeof(struct in6_addr), reg);
|
||||
nft_flow_rule_set_addr_type(flow, FLOW_DISSECTOR_KEY_IPV6_ADDRS);
|
||||
break;
|
||||
case offsetof(struct ipv6hdr, daddr):
|
||||
if (priv->len != sizeof(struct in6_addr))
|
||||
if (!nft_payload_offload_mask(reg, priv->len,
|
||||
sizeof(struct in6_addr)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, dst,
|
||||
sizeof(struct in6_addr), reg);
|
||||
nft_flow_rule_set_addr_type(flow, FLOW_DISSECTOR_KEY_IPV6_ADDRS);
|
||||
break;
|
||||
case offsetof(struct ipv6hdr, nexthdr):
|
||||
if (priv->len != sizeof(__u8))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__u8)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
|
||||
|
@ -331,14 +367,14 @@ static int nft_payload_offload_tcp(struct nft_offload_ctx *ctx,
|
|||
|
||||
switch (priv->offset) {
|
||||
case offsetof(struct tcphdr, source):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src,
|
||||
sizeof(__be16), reg);
|
||||
break;
|
||||
case offsetof(struct tcphdr, dest):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
|
||||
|
@ -359,14 +395,14 @@ static int nft_payload_offload_udp(struct nft_offload_ctx *ctx,
|
|||
|
||||
switch (priv->offset) {
|
||||
case offsetof(struct udphdr, source):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src,
|
||||
sizeof(__be16), reg);
|
||||
break;
|
||||
case offsetof(struct udphdr, dest):
|
||||
if (priv->len != sizeof(__be16))
|
||||
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
|
||||
|
|
Загрузка…
Ссылка в новой задаче