diff options
-rw-r--r-- | include/uapi/linux/netfilter/nf_conntrack_common.h | 4 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 26 |
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 | ||
2272 | static int | 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 | |||
2296 | static int | ||
2273 | ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) | 2297 | ctnetlink_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 | } |