diff options
author | David S. Miller <davem@davemloft.net> | 2015-05-16 16:40:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-16 16:40:22 -0400 |
commit | 1d6057019ee1b0de90697ff10bf84b7028e8bba4 (patch) | |
tree | e4ecabf883d7fa5c8f30d9f9294c50ee1def75de | |
parent | 7e14069651591c81046ffaec13c3dac8cb70f5fb (diff) | |
parent | 960bd2c26421d321e890f1936938196ead41976f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says:
====================
The following patchset contains Netfilter fixes for your net tree, they are:
1) Fix a leak in IPVS, the sysctl table is not released accordingly when
destroying a netns, patch from Tommi Rantala.
2) Fix a build error when TPROXY and socket are built-in but IPv6 defrag is
compiled as module, from Florian Westphal.
3) Fix TCP tracket wrt. RFC5961 challenge ACK when in LAST_ACK state, patch
from Jesper Dangaard Brouer.
4) Fix a bogus WARN_ON() in nf_tables when deleting a set element that stores
a map, from Mirek Kratochvil.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/uapi/linux/netfilter/nf_conntrack_tcp.h | 3 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 2 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 3 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 35 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 4 |
5 files changed, 42 insertions, 5 deletions
diff --git a/include/uapi/linux/netfilter/nf_conntrack_tcp.h b/include/uapi/linux/netfilter/nf_conntrack_tcp.h index 9993a421201c..ef9f80f0f529 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_tcp.h +++ b/include/uapi/linux/netfilter/nf_conntrack_tcp.h | |||
@@ -42,6 +42,9 @@ enum tcp_conntrack { | |||
42 | /* The field td_maxack has been set */ | 42 | /* The field td_maxack has been set */ |
43 | #define IP_CT_TCP_FLAG_MAXACK_SET 0x20 | 43 | #define IP_CT_TCP_FLAG_MAXACK_SET 0x20 |
44 | 44 | ||
45 | /* Marks possibility for expected RFC5961 challenge ACK */ | ||
46 | #define IP_CT_EXP_CHALLENGE_ACK 0x40 | ||
47 | |||
45 | struct nf_ct_tcp_flags { | 48 | struct nf_ct_tcp_flags { |
46 | __u8 flags; | 49 | __u8 flags; |
47 | __u8 mask; | 50 | __u8 mask; |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f70e34a68f70..a0f3e6a3c7d1 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -863,6 +863,7 @@ config NETFILTER_XT_TARGET_TPROXY | |||
863 | depends on NETFILTER_XTABLES | 863 | depends on NETFILTER_XTABLES |
864 | depends on NETFILTER_ADVANCED | 864 | depends on NETFILTER_ADVANCED |
865 | depends on (IPV6 || IPV6=n) | 865 | depends on (IPV6 || IPV6=n) |
866 | depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) | ||
866 | depends on IP_NF_MANGLE | 867 | depends on IP_NF_MANGLE |
867 | select NF_DEFRAG_IPV4 | 868 | select NF_DEFRAG_IPV4 |
868 | select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES | 869 | select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES |
@@ -1356,6 +1357,7 @@ config NETFILTER_XT_MATCH_SOCKET | |||
1356 | depends on NETFILTER_ADVANCED | 1357 | depends on NETFILTER_ADVANCED |
1357 | depends on !NF_CONNTRACK || NF_CONNTRACK | 1358 | depends on !NF_CONNTRACK || NF_CONNTRACK |
1358 | depends on (IPV6 || IPV6=n) | 1359 | depends on (IPV6 || IPV6=n) |
1360 | depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) | ||
1359 | select NF_DEFRAG_IPV4 | 1361 | select NF_DEFRAG_IPV4 |
1360 | select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES | 1362 | select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES |
1361 | help | 1363 | help |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 49532672f66d..285eae3a1454 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -3823,6 +3823,9 @@ static void __net_exit ip_vs_control_net_cleanup_sysctl(struct net *net) | |||
3823 | cancel_work_sync(&ipvs->defense_work.work); | 3823 | cancel_work_sync(&ipvs->defense_work.work); |
3824 | unregister_net_sysctl_table(ipvs->sysctl_hdr); | 3824 | unregister_net_sysctl_table(ipvs->sysctl_hdr); |
3825 | ip_vs_stop_estimator(net, &ipvs->tot_stats); | 3825 | ip_vs_stop_estimator(net, &ipvs->tot_stats); |
3826 | |||
3827 | if (!net_eq(net, &init_net)) | ||
3828 | kfree(ipvs->sysctl_tbl); | ||
3826 | } | 3829 | } |
3827 | 3830 | ||
3828 | #else | 3831 | #else |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 5caa0c41bf26..70383de72054 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -202,7 +202,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | |||
202 | * sES -> sES :-) | 202 | * sES -> sES :-) |
203 | * sFW -> sCW Normal close request answered by ACK. | 203 | * sFW -> sCW Normal close request answered by ACK. |
204 | * sCW -> sCW | 204 | * sCW -> sCW |
205 | * sLA -> sTW Last ACK detected. | 205 | * sLA -> sTW Last ACK detected (RFC5961 challenged) |
206 | * sTW -> sTW Retransmitted last ACK. Remain in the same state. | 206 | * sTW -> sTW Retransmitted last ACK. Remain in the same state. |
207 | * sCL -> sCL | 207 | * sCL -> sCL |
208 | */ | 208 | */ |
@@ -261,7 +261,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | |||
261 | * sES -> sES :-) | 261 | * sES -> sES :-) |
262 | * sFW -> sCW Normal close request answered by ACK. | 262 | * sFW -> sCW Normal close request answered by ACK. |
263 | * sCW -> sCW | 263 | * sCW -> sCW |
264 | * sLA -> sTW Last ACK detected. | 264 | * sLA -> sTW Last ACK detected (RFC5961 challenged) |
265 | * sTW -> sTW Retransmitted last ACK. | 265 | * sTW -> sTW Retransmitted last ACK. |
266 | * sCL -> sCL | 266 | * sCL -> sCL |
267 | */ | 267 | */ |
@@ -906,6 +906,7 @@ static int tcp_packet(struct nf_conn *ct, | |||
906 | 1 : ct->proto.tcp.last_win; | 906 | 1 : ct->proto.tcp.last_win; |
907 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale = | 907 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale = |
908 | ct->proto.tcp.last_wscale; | 908 | ct->proto.tcp.last_wscale; |
909 | ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; | ||
909 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = | 910 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = |
910 | ct->proto.tcp.last_flags; | 911 | ct->proto.tcp.last_flags; |
911 | memset(&ct->proto.tcp.seen[dir], 0, | 912 | memset(&ct->proto.tcp.seen[dir], 0, |
@@ -923,7 +924,9 @@ static int tcp_packet(struct nf_conn *ct, | |||
923 | * may be in sync but we are not. In that case, we annotate | 924 | * may be in sync but we are not. In that case, we annotate |
924 | * the TCP options and let the packet go through. If it is a | 925 | * the TCP options and let the packet go through. If it is a |
925 | * valid SYN packet, the server will reply with a SYN/ACK, and | 926 | * valid SYN packet, the server will reply with a SYN/ACK, and |
926 | * then we'll get in sync. Otherwise, the server ignores it. */ | 927 | * then we'll get in sync. Otherwise, the server potentially |
928 | * responds with a challenge ACK if implementing RFC5961. | ||
929 | */ | ||
927 | if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) { | 930 | if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) { |
928 | struct ip_ct_tcp_state seen = {}; | 931 | struct ip_ct_tcp_state seen = {}; |
929 | 932 | ||
@@ -939,6 +942,13 @@ static int tcp_packet(struct nf_conn *ct, | |||
939 | ct->proto.tcp.last_flags |= | 942 | ct->proto.tcp.last_flags |= |
940 | IP_CT_TCP_FLAG_SACK_PERM; | 943 | IP_CT_TCP_FLAG_SACK_PERM; |
941 | } | 944 | } |
945 | /* Mark the potential for RFC5961 challenge ACK, | ||
946 | * this pose a special problem for LAST_ACK state | ||
947 | * as ACK is intrepretated as ACKing last FIN. | ||
948 | */ | ||
949 | if (old_state == TCP_CONNTRACK_LAST_ACK) | ||
950 | ct->proto.tcp.last_flags |= | ||
951 | IP_CT_EXP_CHALLENGE_ACK; | ||
942 | } | 952 | } |
943 | spin_unlock_bh(&ct->lock); | 953 | spin_unlock_bh(&ct->lock); |
944 | if (LOG_INVALID(net, IPPROTO_TCP)) | 954 | if (LOG_INVALID(net, IPPROTO_TCP)) |
@@ -970,6 +980,25 @@ static int tcp_packet(struct nf_conn *ct, | |||
970 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, | 980 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, |
971 | "nf_ct_tcp: invalid state "); | 981 | "nf_ct_tcp: invalid state "); |
972 | return -NF_ACCEPT; | 982 | return -NF_ACCEPT; |
983 | case TCP_CONNTRACK_TIME_WAIT: | ||
984 | /* RFC5961 compliance cause stack to send "challenge-ACK" | ||
985 | * e.g. in response to spurious SYNs. Conntrack MUST | ||
986 | * not believe this ACK is acking last FIN. | ||
987 | */ | ||
988 | if (old_state == TCP_CONNTRACK_LAST_ACK && | ||
989 | index == TCP_ACK_SET && | ||
990 | ct->proto.tcp.last_dir != dir && | ||
991 | ct->proto.tcp.last_index == TCP_SYN_SET && | ||
992 | (ct->proto.tcp.last_flags & IP_CT_EXP_CHALLENGE_ACK)) { | ||
993 | /* Detected RFC5961 challenge ACK */ | ||
994 | ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; | ||
995 | spin_unlock_bh(&ct->lock); | ||
996 | if (LOG_INVALID(net, IPPROTO_TCP)) | ||
997 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, | ||
998 | "nf_ct_tcp: challenge-ACK ignored "); | ||
999 | return NF_ACCEPT; /* Don't change state */ | ||
1000 | } | ||
1001 | break; | ||
973 | case TCP_CONNTRACK_CLOSE: | 1002 | case TCP_CONNTRACK_CLOSE: |
974 | if (index == TCP_RST_SET | 1003 | if (index == TCP_RST_SET |
975 | && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) | 1004 | && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index ad9d11fb29fd..34ded09317e7 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -4472,9 +4472,9 @@ EXPORT_SYMBOL_GPL(nft_data_init); | |||
4472 | */ | 4472 | */ |
4473 | void nft_data_uninit(const struct nft_data *data, enum nft_data_types type) | 4473 | void nft_data_uninit(const struct nft_data *data, enum nft_data_types type) |
4474 | { | 4474 | { |
4475 | switch (type) { | 4475 | if (type < NFT_DATA_VERDICT) |
4476 | case NFT_DATA_VALUE: | ||
4477 | return; | 4476 | return; |
4477 | switch (type) { | ||
4478 | case NFT_DATA_VERDICT: | 4478 | case NFT_DATA_VERDICT: |
4479 | return nft_verdict_uninit(data); | 4479 | return nft_verdict_uninit(data); |
4480 | default: | 4480 | default: |