mirror of
https://github.com/torvalds/linux
synced 2024-09-06 18:01:05 +00:00
netfilter: conntrack: fix wrong ct->timeout value
(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: a4b4766c3c
("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>
This commit is contained in:
parent
2cdaa3eefe
commit
73db1b8f2b
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue