Skip to content

Commit

Permalink
netfilter: conntrack: fix wrong ct->timeout value
Browse files Browse the repository at this point in the history
[ Upstream commit 73db1b8 ]

(struct nf_conn)->timeout is an interval before the conntrack
confirmed.  After confirmed, it becomes a timestamp.

It is observed that timeout of an unconfirmed conntrack:
- Set by calling ctnetlink_change_timeout(). As a result,
  `nfct_time_stamp` was wrongly added to `ct->timeout` twice.
- Get by calling ctnetlink_dump_timeout(). As a result,
  `nfct_time_stamp` was wrongly subtracted.

Call Trace:
 <TASK>
 dump_stack_lvl
 ctnetlink_dump_timeout
 __ctnetlink_glue_build
 ctnetlink_glue_build
 __nfqnl_enqueue_packet
 nf_queue
 nf_hook_slow
 ip_mc_output
 ? __pfx_ip_finish_output
 ip_send_skb
 ? __pfx_dst_output
 udp_send_skb
 udp_sendmsg
 ? __pfx_ip_generic_getfrag
 sock_sendmsg

Separate the 2 cases in:
- Setting `ct->timeout` in __nf_ct_set_timeout().
- Getting `ct->timeout` in ctnetlink_dump_timeout().

Pablo appends:

Update ctnetlink to set up the timeout _after_ the IPS_CONFIRMED flag is
set on, otherwise conntrack creation via ctnetlink breaks.

Note that the problem described in this patch occurs since the
introduction of the nfnetlink_queue conntrack support, select a
sufficiently old Fixes: tag for -stable kernel to pick up this fix.

Fixes: a4b4766 ("netfilter: nfnetlink_queue: rename related to nfqueue attaching conntrack info")
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Tzung-Bi Shih authored and gregkh committed May 11, 2023
1 parent fc3f262 commit f612ae1
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 5 deletions.
6 changes: 5 additions & 1 deletion include/net/netfilter/nf_conntrack_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ 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);

if (nf_ct_is_confirmed(ct))
WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout);
else
ct->timeout = (u32)timeout;
}

int __nf_ct_change_timeout(struct nf_conn *ct, u64 cta_timeout);
Expand Down
13 changes: 9 additions & 4 deletions net/netfilter/nf_conntrack_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,12 @@ static int ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct)
static int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct,
bool skip_zero)
{
long timeout = nf_ct_expires(ct) / HZ;
long timeout;

if (nf_ct_is_confirmed(ct))
timeout = nf_ct_expires(ct) / HZ;
else
timeout = ct->timeout / HZ;

if (skip_zero && timeout == 0)
return 0;
Expand Down Expand Up @@ -2253,9 +2258,6 @@ ctnetlink_create_conntrack(struct net *net,
if (!cda[CTA_TIMEOUT])
goto err1;

timeout = (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ;
__nf_ct_set_timeout(ct, timeout);

rcu_read_lock();
if (cda[CTA_HELP]) {
char *helpname = NULL;
Expand Down Expand Up @@ -2319,6 +2321,9 @@ ctnetlink_create_conntrack(struct net *net,
/* we must add conntrack extensions before confirmation. */
ct->status |= IPS_CONFIRMED;

timeout = (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ;
__nf_ct_set_timeout(ct, timeout);

if (cda[CTA_STATUS]) {
err = ctnetlink_change_status(ct, cda);
if (err < 0)
Expand Down

0 comments on commit f612ae1

Please sign in to comment.