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

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: David S. Miller <davem@davemloft.net>

+77 -27
+1
include/net/ip_vs.h
··· 889 889 struct delayed_work defense_work; /* Work handler */ 890 890 int drop_rate; 891 891 int drop_counter; 892 + int old_secure_tcp; 892 893 atomic_t dropentry; 893 894 /* locks in ctl.c */ 894 895 spinlock_t dropentry_lock; /* drop entry handling */
+10 -2
net/netfilter/ipvs/ip_vs_app.c
··· 193 193 194 194 mutex_lock(&__ip_vs_app_mutex); 195 195 196 + /* increase the module use count */ 197 + if (!ip_vs_use_count_inc()) { 198 + err = -ENOENT; 199 + goto out_unlock; 200 + } 201 + 196 202 list_for_each_entry(a, &ipvs->app_list, a_list) { 197 203 if (!strcmp(app->name, a->name)) { 198 204 err = -EEXIST; 205 + /* decrease the module use count */ 206 + ip_vs_use_count_dec(); 199 207 goto out_unlock; 200 208 } 201 209 } 202 210 a = kmemdup(app, sizeof(*app), GFP_KERNEL); 203 211 if (!a) { 204 212 err = -ENOMEM; 213 + /* decrease the module use count */ 214 + ip_vs_use_count_dec(); 205 215 goto out_unlock; 206 216 } 207 217 INIT_LIST_HEAD(&a->incs_list); 208 218 list_add(&a->a_list, &ipvs->app_list); 209 - /* increase the module use count */ 210 - ip_vs_use_count_inc(); 211 219 212 220 out_unlock: 213 221 mutex_unlock(&__ip_vs_app_mutex);
+11 -18
net/netfilter/ipvs/ip_vs_ctl.c
··· 93 93 static void update_defense_level(struct netns_ipvs *ipvs) 94 94 { 95 95 struct sysinfo i; 96 - static int old_secure_tcp = 0; 97 96 int availmem; 98 97 int nomem; 99 98 int to_change = -1; ··· 173 174 spin_lock(&ipvs->securetcp_lock); 174 175 switch (ipvs->sysctl_secure_tcp) { 175 176 case 0: 176 - if (old_secure_tcp >= 2) 177 + if (ipvs->old_secure_tcp >= 2) 177 178 to_change = 0; 178 179 break; 179 180 case 1: 180 181 if (nomem) { 181 - if (old_secure_tcp < 2) 182 + if (ipvs->old_secure_tcp < 2) 182 183 to_change = 1; 183 184 ipvs->sysctl_secure_tcp = 2; 184 185 } else { 185 - if (old_secure_tcp >= 2) 186 + if (ipvs->old_secure_tcp >= 2) 186 187 to_change = 0; 187 188 } 188 189 break; 189 190 case 2: 190 191 if (nomem) { 191 - if (old_secure_tcp < 2) 192 + if (ipvs->old_secure_tcp < 2) 192 193 to_change = 1; 193 194 } else { 194 - if (old_secure_tcp >= 2) 195 + if (ipvs->old_secure_tcp >= 2) 195 196 to_change = 0; 196 197 ipvs->sysctl_secure_tcp = 1; 197 198 } 198 199 break; 199 200 case 3: 200 - if (old_secure_tcp < 2) 201 + if (ipvs->old_secure_tcp < 2) 201 202 to_change = 1; 202 203 break; 203 204 } 204 - old_secure_tcp = ipvs->sysctl_secure_tcp; 205 + ipvs->old_secure_tcp = ipvs->sysctl_secure_tcp; 205 206 if (to_change >= 0) 206 207 ip_vs_protocol_timeout_change(ipvs, 207 208 ipvs->sysctl_secure_tcp > 1); ··· 1274 1275 struct ip_vs_service *svc = NULL; 1275 1276 1276 1277 /* increase the module use count */ 1277 - ip_vs_use_count_inc(); 1278 + if (!ip_vs_use_count_inc()) 1279 + return -ENOPROTOOPT; 1278 1280 1279 1281 /* Lookup the scheduler by 'u->sched_name' */ 1280 1282 if (strcmp(u->sched_name, "none")) { ··· 2435 2435 if (copy_from_user(arg, user, len) != 0) 2436 2436 return -EFAULT; 2437 2437 2438 - /* increase the module use count */ 2439 - ip_vs_use_count_inc(); 2440 - 2441 2438 /* Handle daemons since they have another lock */ 2442 2439 if (cmd == IP_VS_SO_SET_STARTDAEMON || 2443 2440 cmd == IP_VS_SO_SET_STOPDAEMON) { ··· 2447 2450 ret = -EINVAL; 2448 2451 if (strscpy(cfg.mcast_ifn, dm->mcast_ifn, 2449 2452 sizeof(cfg.mcast_ifn)) <= 0) 2450 - goto out_dec; 2453 + return ret; 2451 2454 cfg.syncid = dm->syncid; 2452 2455 ret = start_sync_thread(ipvs, &cfg, dm->state); 2453 2456 } else { 2454 2457 ret = stop_sync_thread(ipvs, dm->state); 2455 2458 } 2456 - goto out_dec; 2459 + return ret; 2457 2460 } 2458 2461 2459 2462 mutex_lock(&__ip_vs_mutex); ··· 2548 2551 2549 2552 out_unlock: 2550 2553 mutex_unlock(&__ip_vs_mutex); 2551 - out_dec: 2552 - /* decrease the module use count */ 2553 - ip_vs_use_count_dec(); 2554 - 2555 2554 return ret; 2556 2555 } 2557 2556
+2 -1
net/netfilter/ipvs/ip_vs_pe.c
··· 68 68 struct ip_vs_pe *tmp; 69 69 70 70 /* increase the module use count */ 71 - ip_vs_use_count_inc(); 71 + if (!ip_vs_use_count_inc()) 72 + return -ENOENT; 72 73 73 74 mutex_lock(&ip_vs_pe_mutex); 74 75 /* Make sure that the pe with this name doesn't exist
+2 -1
net/netfilter/ipvs/ip_vs_sched.c
··· 179 179 } 180 180 181 181 /* increase the module use count */ 182 - ip_vs_use_count_inc(); 182 + if (!ip_vs_use_count_inc()) 183 + return -ENOENT; 183 184 184 185 mutex_lock(&ip_vs_sched_mutex); 185 186
+10 -3
net/netfilter/ipvs/ip_vs_sync.c
··· 1762 1762 IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n", 1763 1763 sizeof(struct ip_vs_sync_conn_v0)); 1764 1764 1765 + /* increase the module use count */ 1766 + if (!ip_vs_use_count_inc()) 1767 + return -ENOPROTOOPT; 1768 + 1765 1769 /* Do not hold one mutex and then to block on another */ 1766 1770 for (;;) { 1767 1771 rtnl_lock(); ··· 1896 1892 mutex_unlock(&ipvs->sync_mutex); 1897 1893 rtnl_unlock(); 1898 1894 1899 - /* increase the module use count */ 1900 - ip_vs_use_count_inc(); 1901 - 1902 1895 return 0; 1903 1896 1904 1897 out: ··· 1925 1924 } 1926 1925 kfree(ti); 1927 1926 } 1927 + 1928 + /* decrease the module use count */ 1929 + ip_vs_use_count_dec(); 1928 1930 return result; 1929 1931 1930 1932 out_early: 1931 1933 mutex_unlock(&ipvs->sync_mutex); 1932 1934 rtnl_unlock(); 1935 + 1936 + /* decrease the module use count */ 1937 + ip_vs_use_count_dec(); 1933 1938 return result; 1934 1939 } 1935 1940
+2 -1
net/netfilter/nf_flow_table_core.c
··· 202 202 { 203 203 int err; 204 204 205 + flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; 206 + 205 207 err = rhashtable_insert_fast(&flow_table->rhashtable, 206 208 &flow->tuplehash[0].node, 207 209 nf_flow_offload_rhash_params); ··· 220 218 return err; 221 219 } 222 220 223 - flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; 224 221 return 0; 225 222 } 226 223 EXPORT_SYMBOL_GPL(flow_offload_add);
+1 -1
net/netfilter/nf_tables_offload.c
··· 347 347 348 348 policy = nft_trans_chain_policy(trans); 349 349 err = nft_flow_offload_chain(trans->ctx.chain, &policy, 350 - FLOW_BLOCK_BIND); 350 + FLOW_BLOCK_UNBIND); 351 351 break; 352 352 case NFT_MSG_NEWRULE: 353 353 if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
+38
net/netfilter/nft_payload.c
··· 161 161 162 162 switch (priv->offset) { 163 163 case offsetof(struct ethhdr, h_source): 164 + if (priv->len != ETH_ALEN) 165 + return -EOPNOTSUPP; 166 + 164 167 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs, 165 168 src, ETH_ALEN, reg); 166 169 break; 167 170 case offsetof(struct ethhdr, h_dest): 171 + if (priv->len != ETH_ALEN) 172 + return -EOPNOTSUPP; 173 + 168 174 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs, 169 175 dst, ETH_ALEN, reg); 170 176 break; 177 + default: 178 + return -EOPNOTSUPP; 171 179 } 172 180 173 181 return 0; ··· 189 181 190 182 switch (priv->offset) { 191 183 case offsetof(struct iphdr, saddr): 184 + if (priv->len != sizeof(struct in_addr)) 185 + return -EOPNOTSUPP; 186 + 192 187 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, src, 193 188 sizeof(struct in_addr), reg); 194 189 break; 195 190 case offsetof(struct iphdr, daddr): 191 + if (priv->len != sizeof(struct in_addr)) 192 + return -EOPNOTSUPP; 193 + 196 194 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, dst, 197 195 sizeof(struct in_addr), reg); 198 196 break; 199 197 case offsetof(struct iphdr, protocol): 198 + if (priv->len != sizeof(__u8)) 199 + return -EOPNOTSUPP; 200 + 200 201 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto, 201 202 sizeof(__u8), reg); 202 203 nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT); ··· 225 208 226 209 switch (priv->offset) { 227 210 case offsetof(struct ipv6hdr, saddr): 211 + if (priv->len != sizeof(struct in6_addr)) 212 + return -EOPNOTSUPP; 213 + 228 214 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, src, 229 215 sizeof(struct in6_addr), reg); 230 216 break; 231 217 case offsetof(struct ipv6hdr, daddr): 218 + if (priv->len != sizeof(struct in6_addr)) 219 + return -EOPNOTSUPP; 220 + 232 221 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, dst, 233 222 sizeof(struct in6_addr), reg); 234 223 break; 235 224 case offsetof(struct ipv6hdr, nexthdr): 225 + if (priv->len != sizeof(__u8)) 226 + return -EOPNOTSUPP; 227 + 236 228 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto, 237 229 sizeof(__u8), reg); 238 230 nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT); ··· 281 255 282 256 switch (priv->offset) { 283 257 case offsetof(struct tcphdr, source): 258 + if (priv->len != sizeof(__be16)) 259 + return -EOPNOTSUPP; 260 + 284 261 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src, 285 262 sizeof(__be16), reg); 286 263 break; 287 264 case offsetof(struct tcphdr, dest): 265 + if (priv->len != sizeof(__be16)) 266 + return -EOPNOTSUPP; 267 + 288 268 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst, 289 269 sizeof(__be16), reg); 290 270 break; ··· 309 277 310 278 switch (priv->offset) { 311 279 case offsetof(struct udphdr, source): 280 + if (priv->len != sizeof(__be16)) 281 + return -EOPNOTSUPP; 282 + 312 283 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src, 313 284 sizeof(__be16), reg); 314 285 break; 315 286 case offsetof(struct udphdr, dest): 287 + if (priv->len != sizeof(__be16)) 288 + return -EOPNOTSUPP; 289 + 316 290 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst, 317 291 sizeof(__be16), reg); 318 292 break;