Skip to content

Commit a963d71

Browse files
Kevin Cernekeeummakynes
authored andcommitted
netfilter: ctnetlink: Fix regression in CTA_STATUS processing
The libnetfilter_conntrack userland library always sets IPS_CONFIRMED when building a CTA_STATUS attribute. If this toggles the bit from 0->1, the parser will return an error. On Linux 4.4+ this will cause any NFQA_EXP attribute in the packet to be ignored. This breaks conntrackd's userland helpers because they operate on unconfirmed connections. Instead of returning -EBUSY if the user program asks to modify an unchangeable bit, simply ignore the change. Also, fix the logic so that user programs are allowed to clear the bits that they are allowed to change. Signed-off-by: Kevin Cernekee <cernekee@chromium.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent dfe75ff commit a963d71

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

include/uapi/linux/netfilter/nf_conntrack_common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ enum ip_conntrack_status {
8282
IPS_DYING_BIT = 9,
8383
IPS_DYING = (1 << IPS_DYING_BIT),
8484

85+
/* Bits that cannot be altered from userland. */
86+
IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
87+
IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING),
88+
8589
/* Connection has fixed timeout. */
8690
IPS_FIXED_TIMEOUT_BIT = 10,
8791
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),

net/netfilter/nf_conntrack_netlink.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2269,6 +2269,30 @@ ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct,
22692269
return -ENOSPC;
22702270
}
22712271

2272+
static int
2273+
ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[])
2274+
{
2275+
unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS]));
2276+
unsigned long d = ct->status ^ status;
2277+
2278+
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
2279+
/* SEEN_REPLY bit can only be set */
2280+
return -EBUSY;
2281+
2282+
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
2283+
/* ASSURED bit can only be set */
2284+
return -EBUSY;
2285+
2286+
/* This check is less strict than ctnetlink_change_status()
2287+
* because callers often flip IPS_EXPECTED bits when sending
2288+
* an NFQA_CT attribute to the kernel. So ignore the
2289+
* unchangeable bits but do not error out.
2290+
*/
2291+
ct->status = (status & ~IPS_UNCHANGEABLE_MASK) |
2292+
(ct->status & IPS_UNCHANGEABLE_MASK);
2293+
return 0;
2294+
}
2295+
22722296
static int
22732297
ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
22742298
{
@@ -2280,7 +2304,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
22802304
return err;
22812305
}
22822306
if (cda[CTA_STATUS]) {
2283-
err = ctnetlink_change_status(ct, cda);
2307+
err = ctnetlink_update_status(ct, cda);
22842308
if (err < 0)
22852309
return err;
22862310
}

0 commit comments

Comments
 (0)