Commit fc11078d authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a51a474 52b33b4f
...@@ -889,6 +889,7 @@ struct netns_ipvs { ...@@ -889,6 +889,7 @@ struct netns_ipvs {
struct delayed_work defense_work; /* Work handler */ struct delayed_work defense_work; /* Work handler */
int drop_rate; int drop_rate;
int drop_counter; int drop_counter;
int old_secure_tcp;
atomic_t dropentry; atomic_t dropentry;
/* locks in ctl.c */ /* locks in ctl.c */
spinlock_t dropentry_lock; /* drop entry handling */ spinlock_t dropentry_lock; /* drop entry handling */
......
...@@ -193,21 +193,29 @@ struct ip_vs_app *register_ip_vs_app(struct netns_ipvs *ipvs, struct ip_vs_app * ...@@ -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); 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) { list_for_each_entry(a, &ipvs->app_list, a_list) {
if (!strcmp(app->name, a->name)) { if (!strcmp(app->name, a->name)) {
err = -EEXIST; err = -EEXIST;
/* decrease the module use count */
ip_vs_use_count_dec();
goto out_unlock; goto out_unlock;
} }
} }
a = kmemdup(app, sizeof(*app), GFP_KERNEL); a = kmemdup(app, sizeof(*app), GFP_KERNEL);
if (!a) { if (!a) {
err = -ENOMEM; err = -ENOMEM;
/* decrease the module use count */
ip_vs_use_count_dec();
goto out_unlock; goto out_unlock;
} }
INIT_LIST_HEAD(&a->incs_list); INIT_LIST_HEAD(&a->incs_list);
list_add(&a->a_list, &ipvs->app_list); list_add(&a->a_list, &ipvs->app_list);
/* increase the module use count */
ip_vs_use_count_inc();
out_unlock: out_unlock:
mutex_unlock(&__ip_vs_app_mutex); mutex_unlock(&__ip_vs_app_mutex);
......
...@@ -93,7 +93,6 @@ static bool __ip_vs_addr_is_local_v6(struct net *net, ...@@ -93,7 +93,6 @@ static bool __ip_vs_addr_is_local_v6(struct net *net,
static void update_defense_level(struct netns_ipvs *ipvs) static void update_defense_level(struct netns_ipvs *ipvs)
{ {
struct sysinfo i; struct sysinfo i;
static int old_secure_tcp = 0;
int availmem; int availmem;
int nomem; int nomem;
int to_change = -1; int to_change = -1;
...@@ -174,35 +173,35 @@ static void update_defense_level(struct netns_ipvs *ipvs) ...@@ -174,35 +173,35 @@ static void update_defense_level(struct netns_ipvs *ipvs)
spin_lock(&ipvs->securetcp_lock); spin_lock(&ipvs->securetcp_lock);
switch (ipvs->sysctl_secure_tcp) { switch (ipvs->sysctl_secure_tcp) {
case 0: case 0:
if (old_secure_tcp >= 2) if (ipvs->old_secure_tcp >= 2)
to_change = 0; to_change = 0;
break; break;
case 1: case 1:
if (nomem) { if (nomem) {
if (old_secure_tcp < 2) if (ipvs->old_secure_tcp < 2)
to_change = 1; to_change = 1;
ipvs->sysctl_secure_tcp = 2; ipvs->sysctl_secure_tcp = 2;
} else { } else {
if (old_secure_tcp >= 2) if (ipvs->old_secure_tcp >= 2)
to_change = 0; to_change = 0;
} }
break; break;
case 2: case 2:
if (nomem) { if (nomem) {
if (old_secure_tcp < 2) if (ipvs->old_secure_tcp < 2)
to_change = 1; to_change = 1;
} else { } else {
if (old_secure_tcp >= 2) if (ipvs->old_secure_tcp >= 2)
to_change = 0; to_change = 0;
ipvs->sysctl_secure_tcp = 1; ipvs->sysctl_secure_tcp = 1;
} }
break; break;
case 3: case 3:
if (old_secure_tcp < 2) if (ipvs->old_secure_tcp < 2)
to_change = 1; to_change = 1;
break; break;
} }
old_secure_tcp = ipvs->sysctl_secure_tcp; ipvs->old_secure_tcp = ipvs->sysctl_secure_tcp;
if (to_change >= 0) if (to_change >= 0)
ip_vs_protocol_timeout_change(ipvs, ip_vs_protocol_timeout_change(ipvs,
ipvs->sysctl_secure_tcp > 1); ipvs->sysctl_secure_tcp > 1);
...@@ -1275,7 +1274,8 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, ...@@ -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; struct ip_vs_service *svc = NULL;
/* increase the module use count */ /* 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' */ /* Lookup the scheduler by 'u->sched_name' */
if (strcmp(u->sched_name, "none")) { if (strcmp(u->sched_name, "none")) {
...@@ -2435,9 +2435,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -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) if (copy_from_user(arg, user, len) != 0)
return -EFAULT; return -EFAULT;
/* increase the module use count */
ip_vs_use_count_inc();
/* Handle daemons since they have another lock */ /* Handle daemons since they have another lock */
if (cmd == IP_VS_SO_SET_STARTDAEMON || if (cmd == IP_VS_SO_SET_STARTDAEMON ||
cmd == IP_VS_SO_SET_STOPDAEMON) { cmd == IP_VS_SO_SET_STOPDAEMON) {
...@@ -2450,13 +2447,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2450,13 +2447,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
ret = -EINVAL; ret = -EINVAL;
if (strscpy(cfg.mcast_ifn, dm->mcast_ifn, if (strscpy(cfg.mcast_ifn, dm->mcast_ifn,
sizeof(cfg.mcast_ifn)) <= 0) sizeof(cfg.mcast_ifn)) <= 0)
goto out_dec; return ret;
cfg.syncid = dm->syncid; cfg.syncid = dm->syncid;
ret = start_sync_thread(ipvs, &cfg, dm->state); ret = start_sync_thread(ipvs, &cfg, dm->state);
} else { } else {
ret = stop_sync_thread(ipvs, dm->state); ret = stop_sync_thread(ipvs, dm->state);
} }
goto out_dec; return ret;
} }
mutex_lock(&__ip_vs_mutex); mutex_lock(&__ip_vs_mutex);
...@@ -2551,10 +2548,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2551,10 +2548,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
out_unlock: out_unlock:
mutex_unlock(&__ip_vs_mutex); mutex_unlock(&__ip_vs_mutex);
out_dec:
/* decrease the module use count */
ip_vs_use_count_dec();
return ret; return ret;
} }
......
...@@ -68,7 +68,8 @@ int register_ip_vs_pe(struct ip_vs_pe *pe) ...@@ -68,7 +68,8 @@ int register_ip_vs_pe(struct ip_vs_pe *pe)
struct ip_vs_pe *tmp; struct ip_vs_pe *tmp;
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); if (!ip_vs_use_count_inc())
return -ENOENT;
mutex_lock(&ip_vs_pe_mutex); mutex_lock(&ip_vs_pe_mutex);
/* Make sure that the pe with this name doesn't exist /* Make sure that the pe with this name doesn't exist
......
...@@ -179,7 +179,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) ...@@ -179,7 +179,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
} }
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); if (!ip_vs_use_count_inc())
return -ENOENT;
mutex_lock(&ip_vs_sched_mutex); mutex_lock(&ip_vs_sched_mutex);
......
...@@ -1762,6 +1762,10 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, ...@@ -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", IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n",
sizeof(struct ip_vs_sync_conn_v0)); 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 */ /* Do not hold one mutex and then to block on another */
for (;;) { for (;;) {
rtnl_lock(); rtnl_lock();
...@@ -1892,9 +1896,6 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, ...@@ -1892,9 +1896,6 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
mutex_unlock(&ipvs->sync_mutex); mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock(); rtnl_unlock();
/* increase the module use count */
ip_vs_use_count_inc();
return 0; return 0;
out: out:
...@@ -1924,11 +1925,17 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, ...@@ -1924,11 +1925,17 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
} }
kfree(ti); kfree(ti);
} }
/* decrease the module use count */
ip_vs_use_count_dec();
return result; return result;
out_early: out_early:
mutex_unlock(&ipvs->sync_mutex); mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock(); rtnl_unlock();
/* decrease the module use count */
ip_vs_use_count_dec();
return result; return result;
} }
......
...@@ -202,6 +202,8 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) ...@@ -202,6 +202,8 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
{ {
int err; int err;
flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
err = rhashtable_insert_fast(&flow_table->rhashtable, err = rhashtable_insert_fast(&flow_table->rhashtable,
&flow->tuplehash[0].node, &flow->tuplehash[0].node,
nf_flow_offload_rhash_params); nf_flow_offload_rhash_params);
...@@ -218,7 +220,6 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) ...@@ -218,7 +220,6 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
return err; return err;
} }
flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(flow_offload_add); EXPORT_SYMBOL_GPL(flow_offload_add);
......
...@@ -347,7 +347,7 @@ int nft_flow_rule_offload_commit(struct net *net) ...@@ -347,7 +347,7 @@ int nft_flow_rule_offload_commit(struct net *net)
policy = nft_trans_chain_policy(trans); policy = nft_trans_chain_policy(trans);
err = nft_flow_offload_chain(trans->ctx.chain, &policy, err = nft_flow_offload_chain(trans->ctx.chain, &policy,
FLOW_BLOCK_BIND); FLOW_BLOCK_UNBIND);
break; break;
case NFT_MSG_NEWRULE: case NFT_MSG_NEWRULE:
if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)) if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
......
...@@ -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