From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Tzung-Bi Shih <tzungbi@kernel.org>
Cc: kadlec@netfilter.org, fw@strlen.de,
netfilter-devel@vger.kernel.org, coreteam@netfilter.org,
jiejiang@chromium.org, jasongustaman@chromium.org,
garrick@chromium.org
Subject: Re: [PATCH] netfilter: conntrack: fix wrong ct->timeout value
Date: Mon, 10 Apr 2023 10:33:30 +0200 [thread overview]
Message-ID: <ZDPJ2rHi5fOqu4ga@calendula> (raw)
In-Reply-To: <20230410060935.253503-1-tzungbi@kernel.org>
Hi,
On Mon, Apr 10, 2023 at 02:09:35PM +0800, Tzung-Bi Shih wrote:
> (struct nf_conn)->timeout is an interval before the conntrack
> confirmed. After confirmed, it becomes a timestamp[1].
>
> It is observed that timeout of an unconfirmed conntrack have been
> altered by calling ctnetlink_change_timeout(). As a result,
> `nfct_time_stamp` was wrongly added to `ct->timeout` twice[2].
>
> Differentiate the 2 cases in all `ct->timeout` accesses.
You can just skip refreshing the timeout for unconfirmed conntrack
entries in ctnetlink_change_timeout().
> [1]: https://elixir.bootlin.com/linux/v6.3-rc5/source/net/netfilter/nf_conntrack_core.c#L1257
> [2]: https://elixir.bootlin.com/linux/v6.3-rc5/source/include/net/netfilter/nf_conntrack_core.h#L92
>
> Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
> ---
> include/net/netfilter/nf_conntrack.h | 27 +++++++++++++++++++----
> include/net/netfilter/nf_conntrack_core.h | 2 +-
> net/netfilter/nf_conntrack_core.c | 11 ++++-----
> net/netfilter/nf_conntrack_proto_tcp.c | 4 ++--
> net/netfilter/nf_flow_table_core.c | 4 ++--
> 5 files changed, 32 insertions(+), 16 deletions(-)
>
> diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
> index a72028dbef0c..48e020db3fb3 100644
> --- a/include/net/netfilter/nf_conntrack.h
> +++ b/include/net/netfilter/nf_conntrack.h
> @@ -290,17 +290,36 @@ static inline bool nf_is_loopback_packet(const struct sk_buff *skb)
>
> #define nfct_time_stamp ((u32)(jiffies))
>
> +static inline s32 nf_ct_read_timeout(const struct nf_conn *ct)
> +{
> + s32 timeout;
> +
> + if (nf_ct_is_confirmed(ct))
> + timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
> + else
> + timeout = READ_ONCE(ct->timeout);
> +
> + return timeout;
> +}
> +
> +static inline void nf_ct_write_timeout(struct nf_conn *ct, s32 timeout)
> +{
> + if (nf_ct_is_confirmed(ct))
> + WRITE_ONCE(ct->timeout, timeout + nfct_time_stamp);
> + else
> + WRITE_ONCE(ct->timeout, timeout);
> +}
> +
> /* jiffies until ct expires, 0 if already expired */
> static inline unsigned long nf_ct_expires(const struct nf_conn *ct)
> {
> - s32 timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
> -
> + s32 timeout = nf_ct_read_timeout(ct);
> return max(timeout, 0);
> }
>
> static inline bool nf_ct_is_expired(const struct nf_conn *ct)
> {
> - return (__s32)(READ_ONCE(ct->timeout) - nfct_time_stamp) <= 0;
> + return nf_ct_expires(ct) == 0;
> }
>
> /* use after obtaining a reference count */
> @@ -319,7 +338,7 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
> static inline void nf_ct_offload_timeout(struct nf_conn *ct)
> {
> if (nf_ct_expires(ct) < NF_CT_DAY / 2)
> - WRITE_ONCE(ct->timeout, nfct_time_stamp + NF_CT_DAY);
> + nf_ct_write_timeout(ct, NF_CT_DAY);
> }
>
> struct kernel_param;
> diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
> index 71d1269fe4d4..7a6e49a66d20 100644
> --- a/include/net/netfilter/nf_conntrack_core.h
> +++ b/include/net/netfilter/nf_conntrack_core.h
> @@ -89,7 +89,7 @@ static inline void __nf_ct_set_timeout(struct nf_conn *ct, u64 timeout)
> {
> if (timeout > INT_MAX)
> timeout = INT_MAX;
> - WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout);
> + nf_ct_write_timeout(ct, (u32)timeout);
> }
>
> int __nf_ct_change_timeout(struct nf_conn *ct, u64 cta_timeout);
> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> index db1ea361f2da..47166576c195 100644
> --- a/net/netfilter/nf_conntrack_core.c
> +++ b/net/netfilter/nf_conntrack_core.c
> @@ -657,7 +657,7 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
>
> tstamp = nf_conn_tstamp_find(ct);
> if (tstamp) {
> - s32 timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
> + s32 timeout = nf_ct_read_timeout(ct);
>
> tstamp->stop = ktime_get_real_ns();
> if (timeout < 0)
> @@ -1063,7 +1063,7 @@ static int nf_ct_resolve_clash_harder(struct sk_buff *skb, u32 repl_idx)
> }
>
> /* We want the clashing entry to go away real soon: 1 second timeout. */
> - WRITE_ONCE(loser_ct->timeout, nfct_time_stamp + HZ);
> + nf_ct_write_timeout(loser_ct, HZ);
>
> /* IPS_NAT_CLASH removes the entry automatically on the first
> * reply. Also prevents UDP tracker from moving the entry to
> @@ -2079,11 +2079,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
> goto acct;
>
> /* If not in hash table, timer will not be active yet */
> - if (nf_ct_is_confirmed(ct))
> - extra_jiffies += nfct_time_stamp;
> -
> - if (READ_ONCE(ct->timeout) != extra_jiffies)
> - WRITE_ONCE(ct->timeout, extra_jiffies);
> + if (nf_ct_read_timeout(ct) != extra_jiffies)
> + nf_ct_write_timeout(ct, extra_jiffies);
> acct:
> if (do_acct)
> nf_ct_acct_update(ct, CTINFO2DIR(ctinfo), skb->len);
> diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
> index 4018acb1d674..a2797d026943 100644
> --- a/net/netfilter/nf_conntrack_proto_tcp.c
> +++ b/net/netfilter/nf_conntrack_proto_tcp.c
> @@ -766,7 +766,7 @@ static void __cold nf_tcp_handle_invalid(struct nf_conn *ct,
> "packet (index %d, dir %d) response for index %d lower timeout to %u",
> index, dir, ct->proto.tcp.last_index, timeout);
>
> - WRITE_ONCE(ct->timeout, timeout + nfct_time_stamp);
> + nf_ct_write_timeout(ct, timeout);
> }
> } else {
> ct->proto.tcp.last_index = index;
> @@ -939,7 +939,7 @@ void nf_conntrack_tcp_set_closing(struct nf_conn *ct)
> }
>
> timeout = timeouts[TCP_CONNTRACK_CLOSE];
> - WRITE_ONCE(ct->timeout, timeout + nfct_time_stamp);
> + nf_ct_write_timeout(ct, timeout);
>
> spin_unlock_bh(&ct->lock);
>
> diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
> index 04bd0ed4d2ae..113bd361e537 100644
> --- a/net/netfilter/nf_flow_table_core.c
> +++ b/net/netfilter/nf_flow_table_core.c
> @@ -206,8 +206,8 @@ static void flow_offload_fixup_ct(struct nf_conn *ct)
> if (timeout < 0)
> timeout = 0;
>
> - if (nf_flow_timeout_delta(READ_ONCE(ct->timeout)) > (__s32)timeout)
> - WRITE_ONCE(ct->timeout, nfct_time_stamp + timeout);
> + if (nf_flow_timeout_delta(nf_ct_read_timeout(ct)) > (__s32)timeout)
> + nf_ct_write_timeout(ct, timeout);
> }
>
> static void flow_offload_route_release(struct flow_offload *flow)
> --
> 2.40.0.577.gac1e443424-goog
>
next prev parent reply other threads:[~2023-04-10 8:33 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-10 6:09 [PATCH] netfilter: conntrack: fix wrong ct->timeout value Tzung-Bi Shih
2023-04-10 8:33 ` Pablo Neira Ayuso [this message]
2023-04-10 9:31 ` Pablo Neira Ayuso
2023-04-10 9:59 ` Tzung-Bi Shih
2023-04-12 22:56 ` Pablo Neira Ayuso
2023-04-13 3:23 ` Tzung-Bi Shih
2023-04-13 9:04 ` Pablo Neira Ayuso
2023-04-14 3:52 ` Tzung-Bi Shih
2023-04-14 8:12 ` Pablo Neira Ayuso
2023-04-17 3:41 ` Tzung-Bi Shih
2023-04-18 8:17 ` Pablo Neira Ayuso
2023-04-19 5:20 ` Tzung-Bi Shih
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZDPJ2rHi5fOqu4ga@calendula \
--to=pablo@netfilter.org \
--cc=coreteam@netfilter.org \
--cc=fw@strlen.de \
--cc=garrick@chromium.org \
--cc=jasongustaman@chromium.org \
--cc=jiejiang@chromium.org \
--cc=kadlec@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=tzungbi@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.