From 9431f50b385f08dc1c971457f412e180a1861001 Mon Sep 17 00:00:00 2001 From: suyuan <175338101@qq.com> Date: Wed, 3 Nov 2021 23:17:19 +0800 Subject: [PATCH] Create 370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch --- ...w_table-fix-offloaded-connection-tim.patch | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 root/target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch diff --git a/root/target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch b/root/target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch new file mode 100644 index 00000000..5dac7f5e --- /dev/null +++ b/root/target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch @@ -0,0 +1,115 @@ +From: Felix Fietkau +Date: Wed, 13 Jun 2018 12:33:39 +0200 +Subject: [PATCH] netfilter: nf_flow_table: fix offloaded connection timeout + corner case + +The full teardown of offloaded flows is deferred to a gc work item, +however processing of packets by netfilter needs to happen immediately +after a teardown is requested, because the conntrack state needs to be +fixed up. + +Since the IPS_OFFLOAD_BIT is still kept until the teardown is complete, +the netfilter conntrack gc can accidentally bump the timeout of a +connection where offload was just stopped, causing a conntrack entry +leak. + +Fix this by moving the conntrack timeout bumping from conntrack core to +the nf_flow_offload and add a check to prevent bogus timeout bumps. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1207,18 +1207,6 @@ static bool gc_worker_can_early_drop(con + return false; + } + +-#define DAY (86400 * HZ) +- +-/* Set an arbitrary timeout large enough not to ever expire, this save +- * us a check for the IPS_OFFLOAD_BIT from the packet path via +- * nf_ct_is_expired(). +- */ +-static void nf_ct_offload_timeout(struct nf_conn *ct) +-{ +- if (nf_ct_expires(ct) < DAY / 2) +- ct->timeout = nfct_time_stamp + DAY; +-} +- + static void gc_worker(struct work_struct *work) + { + unsigned long end_time = jiffies + GC_SCAN_MAX_DURATION; +@@ -1250,11 +1238,9 @@ static void gc_worker(struct work_struct + + tmp = nf_ct_tuplehash_to_ctrack(h); + + scanned++; +- if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) { +- nf_ct_offload_timeout(tmp); ++ if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) + continue; +- } + + if (nf_ct_is_expired(tmp)) { + nf_ct_gc_expired(tmp); +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -198,10 +198,29 @@ static const struct rhashtable_params nf + .automatic_shrinking = true, + }; + ++#define DAY (86400 * HZ) ++ ++/* Set an arbitrary timeout large enough not to ever expire, this save ++ * us a check for the IPS_OFFLOAD_BIT from the packet path via ++ * nf_ct_is_expired(). ++ */ ++static void nf_ct_offload_timeout(struct flow_offload *flow) ++{ ++ struct flow_offload_entry *entry; ++ struct nf_conn *ct; ++ ++ entry = container_of(flow, struct flow_offload_entry, flow); ++ ct = entry->ct; ++ ++ if (nf_ct_expires(ct) < DAY / 2) ++ ct->timeout = nfct_time_stamp + DAY; ++} ++ + int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) + { + int err; + ++ nf_ct_offload_timeout(flow); + flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; + + err = rhashtable_insert_fast(&flow_table->rhashtable, +@@ -304,6 +323,7 @@ nf_flow_table_iterate(struct nf_flowtabl + rhashtable_walk_start(&hti); + + while ((tuplehash = rhashtable_walk_next(&hti))) { ++ + if (IS_ERR(tuplehash)) { + if (PTR_ERR(tuplehash) != -EAGAIN) { + err = PTR_ERR(tuplehash); +@@ -328,10 +348,17 @@ static void nf_flow_offload_gc_step(stru + { + struct nf_flowtable *flow_table = data; + struct flow_offload_entry *e; ++ bool teardown; + + e = container_of(flow, struct flow_offload_entry, flow); +- if (nf_flow_has_expired(flow) || nf_ct_is_dying(e->ct) || +- (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN))) ++ ++ teardown = flow->flags & (FLOW_OFFLOAD_DYING | ++ FLOW_OFFLOAD_TEARDOWN); ++ ++ if (!teardown) ++ nf_ct_offload_timeout(flow); ++ ++ if (nf_flow_has_expired(flow) || teardown) + flow_offload_del(flow_table, flow); + } +