Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

====================
Netfilter/IPVS fixes for net

The following patchset contains Netfilter/IPVS fixes for net:

1) Fix crash on flowtable due to race between garbage collection
   and insertion.

2) Restore callback unbinding in netfilter offloads.

3) Fix races on IPVS module removal, from Davide Caratti.

4) Make old_secure_tcp per-netns to fix sysbot report,
   from Eric Dumazet.

5) Validate matching length in netfilter offloads, from wenxu.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Oct 27, 2019
2 parents 1a51a47 + 52b33b4 commit fc11078
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 27 deletions.
1 change: 1 addition & 0 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ struct netns_ipvs {
struct delayed_work defense_work; /* Work handler */
int drop_rate;
int drop_counter;
int old_secure_tcp;
atomic_t dropentry;
/* locks in ctl.c */
spinlock_t dropentry_lock; /* drop entry handling */
Expand Down
12 changes: 10 additions & 2 deletions net/netfilter/ipvs/ip_vs_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,21 +193,29 @@ struct ip_vs_app *register_ip_vs_app(struct netns_ipvs *ipvs, struct ip_vs_app *

mutex_lock(&__ip_vs_app_mutex);

/* increase the module use count */
if (!ip_vs_use_count_inc()) {
err = -ENOENT;
goto out_unlock;
}

list_for_each_entry(a, &ipvs->app_list, a_list) {
if (!strcmp(app->name, a->name)) {
err = -EEXIST;
/* decrease the module use count */
ip_vs_use_count_dec();
goto out_unlock;
}
}
a = kmemdup(app, sizeof(*app), GFP_KERNEL);
if (!a) {
err = -ENOMEM;
/* decrease the module use count */
ip_vs_use_count_dec();
goto out_unlock;
}
INIT_LIST_HEAD(&a->incs_list);
list_add(&a->a_list, &ipvs->app_list);
/* increase the module use count */
ip_vs_use_count_inc();

out_unlock:
mutex_unlock(&__ip_vs_app_mutex);
Expand Down
29 changes: 11 additions & 18 deletions net/netfilter/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ static bool __ip_vs_addr_is_local_v6(struct net *net,
static void update_defense_level(struct netns_ipvs *ipvs)
{
struct sysinfo i;
static int old_secure_tcp = 0;
int availmem;
int nomem;
int to_change = -1;
Expand Down Expand Up @@ -174,35 +173,35 @@ static void update_defense_level(struct netns_ipvs *ipvs)
spin_lock(&ipvs->securetcp_lock);
switch (ipvs->sysctl_secure_tcp) {
case 0:
if (old_secure_tcp >= 2)
if (ipvs->old_secure_tcp >= 2)
to_change = 0;
break;
case 1:
if (nomem) {
if (old_secure_tcp < 2)
if (ipvs->old_secure_tcp < 2)
to_change = 1;
ipvs->sysctl_secure_tcp = 2;
} else {
if (old_secure_tcp >= 2)
if (ipvs->old_secure_tcp >= 2)
to_change = 0;
}
break;
case 2:
if (nomem) {
if (old_secure_tcp < 2)
if (ipvs->old_secure_tcp < 2)
to_change = 1;
} else {
if (old_secure_tcp >= 2)
if (ipvs->old_secure_tcp >= 2)
to_change = 0;
ipvs->sysctl_secure_tcp = 1;
}
break;
case 3:
if (old_secure_tcp < 2)
if (ipvs->old_secure_tcp < 2)
to_change = 1;
break;
}
old_secure_tcp = ipvs->sysctl_secure_tcp;
ipvs->old_secure_tcp = ipvs->sysctl_secure_tcp;
if (to_change >= 0)
ip_vs_protocol_timeout_change(ipvs,
ipvs->sysctl_secure_tcp > 1);
Expand Down Expand Up @@ -1275,7 +1274,8 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
struct ip_vs_service *svc = NULL;

/* increase the module use count */
ip_vs_use_count_inc();
if (!ip_vs_use_count_inc())
return -ENOPROTOOPT;

/* Lookup the scheduler by 'u->sched_name' */
if (strcmp(u->sched_name, "none")) {
Expand Down Expand Up @@ -2435,9 +2435,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
if (copy_from_user(arg, user, len) != 0)
return -EFAULT;

/* increase the module use count */
ip_vs_use_count_inc();

/* Handle daemons since they have another lock */
if (cmd == IP_VS_SO_SET_STARTDAEMON ||
cmd == IP_VS_SO_SET_STOPDAEMON) {
Expand All @@ -2450,13 +2447,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
ret = -EINVAL;
if (strscpy(cfg.mcast_ifn, dm->mcast_ifn,
sizeof(cfg.mcast_ifn)) <= 0)
goto out_dec;
return ret;
cfg.syncid = dm->syncid;
ret = start_sync_thread(ipvs, &cfg, dm->state);
} else {
ret = stop_sync_thread(ipvs, dm->state);
}
goto out_dec;
return ret;
}

mutex_lock(&__ip_vs_mutex);
Expand Down Expand Up @@ -2551,10 +2548,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)

out_unlock:
mutex_unlock(&__ip_vs_mutex);
out_dec:
/* decrease the module use count */
ip_vs_use_count_dec();

return ret;
}

Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/ipvs/ip_vs_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ int register_ip_vs_pe(struct ip_vs_pe *pe)
struct ip_vs_pe *tmp;

/* increase the module use count */
ip_vs_use_count_inc();
if (!ip_vs_use_count_inc())
return -ENOENT;

mutex_lock(&ip_vs_pe_mutex);
/* Make sure that the pe with this name doesn't exist
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/ipvs/ip_vs_sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
}

/* increase the module use count */
ip_vs_use_count_inc();
if (!ip_vs_use_count_inc())
return -ENOENT;

mutex_lock(&ip_vs_sched_mutex);

Expand Down
13 changes: 10 additions & 3 deletions net/netfilter/ipvs/ip_vs_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,10 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n",
sizeof(struct ip_vs_sync_conn_v0));

/* increase the module use count */
if (!ip_vs_use_count_inc())
return -ENOPROTOOPT;

/* Do not hold one mutex and then to block on another */
for (;;) {
rtnl_lock();
Expand Down Expand Up @@ -1892,9 +1896,6 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock();

/* increase the module use count */
ip_vs_use_count_inc();

return 0;

out:
Expand Down Expand Up @@ -1924,11 +1925,17 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
}
kfree(ti);
}

/* decrease the module use count */
ip_vs_use_count_dec();
return result;

out_early:
mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock();

/* decrease the module use count */
ip_vs_use_count_dec();
return result;
}

Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/nf_flow_table_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
{
int err;

flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;

err = rhashtable_insert_fast(&flow_table->rhashtable,
&flow->tuplehash[0].node,
nf_flow_offload_rhash_params);
Expand All @@ -218,7 +220,6 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
return err;
}

flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
return 0;
}
EXPORT_SYMBOL_GPL(flow_offload_add);
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nf_tables_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ int nft_flow_rule_offload_commit(struct net *net)

policy = nft_trans_chain_policy(trans);
err = nft_flow_offload_chain(trans->ctx.chain, &policy,
FLOW_BLOCK_BIND);
FLOW_BLOCK_UNBIND);
break;
case NFT_MSG_NEWRULE:
if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
Expand Down
38 changes: 38 additions & 0 deletions net/netfilter/nft_payload.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,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)
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)
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
dst, ETH_ALEN, reg);
break;
default:
return -EOPNOTSUPP;
}

return 0;
Expand All @@ -181,14 +189,23 @@ 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))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, src,
sizeof(struct in_addr), reg);
break;
case offsetof(struct iphdr, daddr):
if (priv->len != sizeof(struct in_addr))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, dst,
sizeof(struct in_addr), reg);
break;
case offsetof(struct iphdr, protocol):
if (priv->len != sizeof(__u8))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
sizeof(__u8), reg);
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
Expand All @@ -208,14 +225,23 @@ 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))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, src,
sizeof(struct in6_addr), reg);
break;
case offsetof(struct ipv6hdr, daddr):
if (priv->len != sizeof(struct in6_addr))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, dst,
sizeof(struct in6_addr), reg);
break;
case offsetof(struct ipv6hdr, nexthdr):
if (priv->len != sizeof(__u8))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
sizeof(__u8), reg);
nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
Expand Down Expand Up @@ -255,10 +281,16 @@ static int nft_payload_offload_tcp(struct nft_offload_ctx *ctx,

switch (priv->offset) {
case offsetof(struct tcphdr, source):
if (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))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
sizeof(__be16), reg);
break;
Expand All @@ -277,10 +309,16 @@ static int nft_payload_offload_udp(struct nft_offload_ctx *ctx,

switch (priv->offset) {
case offsetof(struct udphdr, source):
if (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))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
sizeof(__be16), reg);
break;
Expand Down

0 comments on commit fc11078

Please sign in to comment.