aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Cernekee <cernekee@chromium.org>2017-01-26 17:49:43 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2017-02-06 06:48:26 -0500
commita963d710f367f68cd13d562a07db55ccb8daade9 (patch)
treef2f33bbecd14af82f866c6297ac6f5607ba8a90f
parentdfe75ff8ca74f54b0fa5a326a1aa9afa485ed802 (diff)
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>
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_common.h4
-rw-r--r--net/netfilter/nf_conntrack_netlink.c26
2 files changed, 29 insertions, 1 deletions
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index 6d074d14ee27..6a8e33dd4ecb 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -82,6 +82,10 @@ enum ip_conntrack_status {
82 IPS_DYING_BIT = 9, 82 IPS_DYING_BIT = 9,
83 IPS_DYING = (1 << IPS_DYING_BIT), 83 IPS_DYING = (1 << IPS_DYING_BIT),
84 84
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
85 /* Connection has fixed timeout. */ 89 /* Connection has fixed timeout. */
86 IPS_FIXED_TIMEOUT_BIT = 10, 90 IPS_FIXED_TIMEOUT_BIT = 10,
87 IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), 91 IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 27540455dc62..bf04b7e9d6f7 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2270,6 +2270,30 @@ nla_put_failure:
2270} 2270}
2271 2271
2272static int 2272static int
2273ctnetlink_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
2296static int
2273ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) 2297ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
2274{ 2298{
2275 int err; 2299 int err;
@@ -2280,7 +2304,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
2280 return err; 2304 return err;
2281 } 2305 }
2282 if (cda[CTA_STATUS]) { 2306 if (cda[CTA_STATUS]) {
2283 err = ctnetlink_change_status(ct, cda); 2307 err = ctnetlink_update_status(ct, cda);
2284 if (err < 0) 2308 if (err < 0)
2285 return err; 2309 return err;
2286 } 2310 }