Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Kubecek <mkubecek@suse.cz>2019-07-21 19:42:03 +0200
committerMichal Kubecek <mkubecek@suse.cz>2019-07-21 19:42:03 +0200
commit8e9a0066dd5e4379ba68bb24bc995b5175b4d7f9 (patch)
tree3f8b1add5c565479515dc1ae8f3a03daeb36e612
parent93f0a5440dff662b2fd94f792da42cdd37724022 (diff)
Revert "netfilter: conntrack: remove helper hook again"
(http://lkml.kernel.org/r/20190718092128.zbw4qappq6jsb4ja@breakpoint.cc).
-rw-r--r--patches.suse/Revert-netfilter-conntrack-remove-helper-hook-again.patch236
-rw-r--r--series.conf1
2 files changed, 237 insertions, 0 deletions
diff --git a/patches.suse/Revert-netfilter-conntrack-remove-helper-hook-again.patch b/patches.suse/Revert-netfilter-conntrack-remove-helper-hook-again.patch
new file mode 100644
index 0000000000..f3f4426144
--- /dev/null
+++ b/patches.suse/Revert-netfilter-conntrack-remove-helper-hook-again.patch
@@ -0,0 +1,236 @@
+From: Michal Kubecek <mkubecek@suse.cz>
+Date: Sun, 21 Jul 2019 19:35:57 +0200
+Subject: Revert "netfilter: conntrack: remove helper hook again"
+Patch-mainline: Not yet, upstream discussion not finished
+References: http://lkml.kernel.org/r/20190718092128.zbw4qappq6jsb4ja@breakpoint.cc
+
+This reverts commit 827318feb69cb07ed58bb9b9dd6c2eaa81a116ad.
+
+This commit was found to break userspace conntrack helpers, see
+
+ http://lkml.kernel.org/r/20190718092128.zbw4qappq6jsb4ja@breakpoint.cc
+
+Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
+---
+ net/netfilter/nf_conntrack_proto.c | 142 +++++++++++++++++++++--------
+ 1 file changed, 106 insertions(+), 36 deletions(-)
+
+--- a/net/netfilter/nf_conntrack_proto.c
++++ b/net/netfilter/nf_conntrack_proto.c
+@@ -120,55 +120,55 @@ const struct nf_conntrack_l4proto *nf_ct_l4proto_find(u8 l4proto)
+ };
+ EXPORT_SYMBOL_GPL(nf_ct_l4proto_find);
+
+-static unsigned int nf_confirm(struct sk_buff *skb,
+- unsigned int protoff,
+- struct nf_conn *ct,
+- enum ip_conntrack_info ctinfo)
++static unsigned int ipv4_helper(void *priv,
++ struct sk_buff *skb,
++ const struct nf_hook_state *state)
+ {
++ struct nf_conn *ct;
++ enum ip_conntrack_info ctinfo;
+ const struct nf_conn_help *help;
++ const struct nf_conntrack_helper *helper;
++
++ /* This is where we call the helper: as the packet goes out. */
++ ct = nf_ct_get(skb, &ctinfo);
++ if (!ct || ctinfo == IP_CT_RELATED_REPLY)
++ return NF_ACCEPT;
+
+ help = nfct_help(ct);
+- if (help) {
+- const struct nf_conntrack_helper *helper;
+- int ret;
+-
+- /* rcu_read_lock()ed by nf_hook_thresh */
+- helper = rcu_dereference(help->helper);
+- if (helper) {
+- ret = helper->help(skb,
+- protoff,
+- ct, ctinfo);
+- if (ret != NF_ACCEPT)
+- return ret;
+- }
+- }
++ if (!help)
++ return NF_ACCEPT;
+
+- if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
+- !nf_is_loopback_packet(skb)) {
+- if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
+- NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
+- return NF_DROP;
+- }
+- }
++ /* rcu_read_lock()ed by nf_hook_thresh */
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return NF_ACCEPT;
+
+- /* We've seen it coming out the other side: confirm it */
+- return nf_conntrack_confirm(skb);
++ return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
++ ct, ctinfo);
+ }
+
+ static unsigned int ipv4_confirm(void *priv,
+ struct sk_buff *skb,
+ const struct nf_hook_state *state)
+ {
+- enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct;
++ enum ip_conntrack_info ctinfo;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct || ctinfo == IP_CT_RELATED_REPLY)
+- return nf_conntrack_confirm(skb);
++ goto out;
+
+- return nf_confirm(skb,
+- skb_network_offset(skb) + ip_hdrlen(skb),
+- ct, ctinfo);
++ /* adjust seqs for loopback traffic only in outgoing direction */
++ if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
++ !nf_is_loopback_packet(skb)) {
++ if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
++ NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
++ return NF_DROP;
++ }
++ }
++out:
++ /* We've seen it coming out the other side: confirm it */
++ return nf_conntrack_confirm(skb);
+ }
+
+ static unsigned int ipv4_conntrack_in(void *priv,
+@@ -216,12 +216,24 @@ static const struct nf_hook_ops ipv4_conntrack_ops[] = {
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP_PRI_CONNTRACK,
+ },
++ {
++ .hook = ipv4_helper,
++ .pf = NFPROTO_IPV4,
++ .hooknum = NF_INET_POST_ROUTING,
++ .priority = NF_IP_PRI_CONNTRACK_HELPER,
++ },
+ {
+ .hook = ipv4_confirm,
+ .pf = NFPROTO_IPV4,
+ .hooknum = NF_INET_POST_ROUTING,
+ .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
+ },
++ {
++ .hook = ipv4_helper,
++ .pf = NFPROTO_IPV4,
++ .hooknum = NF_INET_LOCAL_IN,
++ .priority = NF_IP_PRI_CONNTRACK_HELPER,
++ },
+ {
+ .hook = ipv4_confirm,
+ .pf = NFPROTO_IPV4,
+@@ -367,21 +379,31 @@ static unsigned int ipv6_confirm(void *priv,
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+ unsigned char pnum = ipv6_hdr(skb)->nexthdr;
+- __be16 frag_off;
+ int protoff;
++ __be16 frag_off;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct || ctinfo == IP_CT_RELATED_REPLY)
+- return nf_conntrack_confirm(skb);
++ goto out;
+
+ protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
+ &frag_off);
+ if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
+ pr_debug("proto header not found\n");
+- return nf_conntrack_confirm(skb);
++ goto out;
+ }
+
+- return nf_confirm(skb, protoff, ct, ctinfo);
++ /* adjust seqs for loopback traffic only in outgoing direction */
++ if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
++ !nf_is_loopback_packet(skb)) {
++ if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
++ NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
++ return NF_DROP;
++ }
++ }
++out:
++ /* We've seen it coming out the other side: confirm it */
++ return nf_conntrack_confirm(skb);
+ }
+
+ static unsigned int ipv6_conntrack_in(void *priv,
+@@ -398,6 +420,42 @@ static unsigned int ipv6_conntrack_local(void *priv,
+ return nf_conntrack_in(skb, state);
+ }
+
++static unsigned int ipv6_helper(void *priv,
++ struct sk_buff *skb,
++ const struct nf_hook_state *state)
++{
++ struct nf_conn *ct;
++ const struct nf_conn_help *help;
++ const struct nf_conntrack_helper *helper;
++ enum ip_conntrack_info ctinfo;
++ __be16 frag_off;
++ int protoff;
++ u8 nexthdr;
++
++ /* This is where we call the helper: as the packet goes out. */
++ ct = nf_ct_get(skb, &ctinfo);
++ if (!ct || ctinfo == IP_CT_RELATED_REPLY)
++ return NF_ACCEPT;
++
++ help = nfct_help(ct);
++ if (!help)
++ return NF_ACCEPT;
++ /* rcu_read_lock()ed by nf_hook_thresh */
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return NF_ACCEPT;
++
++ nexthdr = ipv6_hdr(skb)->nexthdr;
++ protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
++ &frag_off);
++ if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
++ pr_debug("proto header not found\n");
++ return NF_ACCEPT;
++ }
++
++ return helper->help(skb, protoff, ct, ctinfo);
++}
++
+ static const struct nf_hook_ops ipv6_conntrack_ops[] = {
+ {
+ .hook = ipv6_conntrack_in,
+@@ -411,12 +469,24 @@ static const struct nf_hook_ops ipv6_conntrack_ops[] = {
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP6_PRI_CONNTRACK,
+ },
++ {
++ .hook = ipv6_helper,
++ .pf = NFPROTO_IPV6,
++ .hooknum = NF_INET_POST_ROUTING,
++ .priority = NF_IP6_PRI_CONNTRACK_HELPER,
++ },
+ {
+ .hook = ipv6_confirm,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_POST_ROUTING,
+ .priority = NF_IP6_PRI_LAST,
+ },
++ {
++ .hook = ipv6_helper,
++ .pf = NFPROTO_IPV6,
++ .hooknum = NF_INET_LOCAL_IN,
++ .priority = NF_IP6_PRI_CONNTRACK_HELPER,
++ },
+ {
+ .hook = ipv6_confirm,
+ .pf = NFPROTO_IPV6,
diff --git a/series.conf b/series.conf
index d9d766aaab..dc7df8a2f2 100644
--- a/series.conf
+++ b/series.conf
@@ -280,6 +280,7 @@
# Netfilter
########################################################
patches.suse/netfilter-ip_conntrack_slp.patch
+ patches.suse/Revert-netfilter-conntrack-remove-helper-hook-again.patch
########################################################
# NFS