diff options
| -rw-r--r-- | include/uapi/linux/netfilter/nf_conntrack_common.h | 4 | ||||
| -rw-r--r-- | include/uapi/linux/netfilter/nfnetlink_queue.h | 2 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_hash_gen.h | 2 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_list_set.c | 9 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 39 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 43 | ||||
| -rw-r--r-- | net/netfilter/nfnetlink.c | 2 | ||||
| -rw-r--r-- | net/netfilter/xt_hashlimit.c | 25 |
8 files changed, 86 insertions, 40 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/include/uapi/linux/netfilter/nfnetlink_queue.h b/include/uapi/linux/netfilter/nfnetlink_queue.h index ae30841ff94e..d42f0396fe30 100644 --- a/include/uapi/linux/netfilter/nfnetlink_queue.h +++ b/include/uapi/linux/netfilter/nfnetlink_queue.h | |||
| @@ -36,7 +36,7 @@ enum nfqnl_vlan_attr { | |||
| 36 | NFQA_VLAN_TCI, /* __be16 skb htons(vlan_tci) */ | 36 | NFQA_VLAN_TCI, /* __be16 skb htons(vlan_tci) */ |
| 37 | __NFQA_VLAN_MAX, | 37 | __NFQA_VLAN_MAX, |
| 38 | }; | 38 | }; |
| 39 | #define NFQA_VLAN_MAX (__NFQA_VLAN_MAX + 1) | 39 | #define NFQA_VLAN_MAX (__NFQA_VLAN_MAX - 1) |
| 40 | 40 | ||
| 41 | enum nfqnl_attr_type { | 41 | enum nfqnl_attr_type { |
| 42 | NFQA_UNSPEC, | 42 | NFQA_UNSPEC, |
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 1b05d4a7d5a1..f236c0bc7b3f 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h | |||
| @@ -897,7 +897,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 897 | continue; | 897 | continue; |
| 898 | data = ahash_data(n, j, dsize); | 898 | data = ahash_data(n, j, dsize); |
| 899 | memcpy(tmp->value + k * dsize, data, dsize); | 899 | memcpy(tmp->value + k * dsize, data, dsize); |
| 900 | set_bit(j, tmp->used); | 900 | set_bit(k, tmp->used); |
| 901 | k++; | 901 | k++; |
| 902 | } | 902 | } |
| 903 | tmp->pos = k; | 903 | tmp->pos = k; |
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index 51077c53d76b..178d4eba013b 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c | |||
| @@ -260,11 +260,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 260 | else | 260 | else |
| 261 | prev = e; | 261 | prev = e; |
| 262 | } | 262 | } |
| 263 | |||
| 264 | /* If before/after is used on an empty set */ | ||
| 265 | if ((d->before > 0 && !next) || | ||
| 266 | (d->before < 0 && !prev)) | ||
| 267 | return -IPSET_ERR_REF_EXIST; | ||
| 268 | |||
| 263 | /* Re-add already existing element */ | 269 | /* Re-add already existing element */ |
| 264 | if (n) { | 270 | if (n) { |
| 265 | if ((d->before > 0 && !next) || | ||
| 266 | (d->before < 0 && !prev)) | ||
| 267 | return -IPSET_ERR_REF_EXIST; | ||
| 268 | if (!flag_exist) | 271 | if (!flag_exist) |
| 269 | return -IPSET_ERR_EXIST; | 272 | return -IPSET_ERR_EXIST; |
| 270 | /* Update extensions */ | 273 | /* Update extensions */ |
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 7341adf7059d..6dc44d9b4190 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
| @@ -188,6 +188,26 @@ nf_ct_helper_ext_add(struct nf_conn *ct, | |||
| 188 | } | 188 | } |
| 189 | EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); | 189 | EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); |
| 190 | 190 | ||
| 191 | static struct nf_conntrack_helper * | ||
| 192 | nf_ct_lookup_helper(struct nf_conn *ct, struct net *net) | ||
| 193 | { | ||
| 194 | if (!net->ct.sysctl_auto_assign_helper) { | ||
| 195 | if (net->ct.auto_assign_helper_warned) | ||
| 196 | return NULL; | ||
| 197 | if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)) | ||
| 198 | return NULL; | ||
| 199 | pr_info("nf_conntrack: default automatic helper assignment " | ||
| 200 | "has been turned off for security reasons and CT-based " | ||
| 201 | " firewall rule not found. Use the iptables CT target " | ||
| 202 | "to attach helpers instead.\n"); | ||
| 203 | net->ct.auto_assign_helper_warned = 1; | ||
| 204 | return NULL; | ||
| 205 | } | ||
| 206 | |||
| 207 | return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 191 | int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, | 211 | int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, |
| 192 | gfp_t flags) | 212 | gfp_t flags) |
| 193 | { | 213 | { |
| @@ -213,21 +233,14 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, | |||
| 213 | } | 233 | } |
| 214 | 234 | ||
| 215 | help = nfct_help(ct); | 235 | help = nfct_help(ct); |
| 216 | if (net->ct.sysctl_auto_assign_helper && helper == NULL) { | ||
| 217 | helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
| 218 | if (unlikely(!net->ct.auto_assign_helper_warned && helper)) { | ||
| 219 | pr_info("nf_conntrack: automatic helper " | ||
| 220 | "assignment is deprecated and it will " | ||
| 221 | "be removed soon. Use the iptables CT target " | ||
| 222 | "to attach helpers instead.\n"); | ||
| 223 | net->ct.auto_assign_helper_warned = true; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | 236 | ||
| 227 | if (helper == NULL) { | 237 | if (helper == NULL) { |
| 228 | if (help) | 238 | helper = nf_ct_lookup_helper(ct, net); |
| 229 | RCU_INIT_POINTER(help->helper, NULL); | 239 | if (helper == NULL) { |
| 230 | return 0; | 240 | if (help) |
| 241 | RCU_INIT_POINTER(help->helper, NULL); | ||
| 242 | return 0; | ||
| 243 | } | ||
| 231 | } | 244 | } |
| 232 | 245 | ||
| 233 | if (help == NULL) { | 246 | if (help == NULL) { |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 27540455dc62..6806b5e73567 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
| @@ -1478,14 +1478,23 @@ static int ctnetlink_change_helper(struct nf_conn *ct, | |||
| 1478 | struct nlattr *helpinfo = NULL; | 1478 | struct nlattr *helpinfo = NULL; |
| 1479 | int err; | 1479 | int err; |
| 1480 | 1480 | ||
| 1481 | /* don't change helper of sibling connections */ | ||
| 1482 | if (ct->master) | ||
| 1483 | return -EBUSY; | ||
| 1484 | |||
| 1485 | err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo); | 1481 | err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo); |
| 1486 | if (err < 0) | 1482 | if (err < 0) |
| 1487 | return err; | 1483 | return err; |
| 1488 | 1484 | ||
| 1485 | /* don't change helper of sibling connections */ | ||
| 1486 | if (ct->master) { | ||
| 1487 | /* If we try to change the helper to the same thing twice, | ||
| 1488 | * treat the second attempt as a no-op instead of returning | ||
| 1489 | * an error. | ||
| 1490 | */ | ||
| 1491 | if (help && help->helper && | ||
| 1492 | !strcmp(help->helper->name, helpname)) | ||
| 1493 | return 0; | ||
| 1494 | else | ||
| 1495 | return -EBUSY; | ||
| 1496 | } | ||
| 1497 | |||
| 1489 | if (!strcmp(helpname, "")) { | 1498 | if (!strcmp(helpname, "")) { |
| 1490 | if (help && help->helper) { | 1499 | if (help && help->helper) { |
| 1491 | /* we had a helper before ... */ | 1500 | /* we had a helper before ... */ |
| @@ -2270,6 +2279,30 @@ nla_put_failure: | |||
| 2270 | } | 2279 | } |
| 2271 | 2280 | ||
| 2272 | static int | 2281 | static int |
| 2282 | ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[]) | ||
| 2283 | { | ||
| 2284 | unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); | ||
| 2285 | unsigned long d = ct->status ^ status; | ||
| 2286 | |||
| 2287 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) | ||
| 2288 | /* SEEN_REPLY bit can only be set */ | ||
| 2289 | return -EBUSY; | ||
| 2290 | |||
| 2291 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) | ||
| 2292 | /* ASSURED bit can only be set */ | ||
| 2293 | return -EBUSY; | ||
| 2294 | |||
| 2295 | /* This check is less strict than ctnetlink_change_status() | ||
| 2296 | * because callers often flip IPS_EXPECTED bits when sending | ||
| 2297 | * an NFQA_CT attribute to the kernel. So ignore the | ||
| 2298 | * unchangeable bits but do not error out. | ||
| 2299 | */ | ||
| 2300 | ct->status = (status & ~IPS_UNCHANGEABLE_MASK) | | ||
| 2301 | (ct->status & IPS_UNCHANGEABLE_MASK); | ||
| 2302 | return 0; | ||
| 2303 | } | ||
| 2304 | |||
| 2305 | static int | ||
| 2273 | ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) | 2306 | ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) |
| 2274 | { | 2307 | { |
| 2275 | int err; | 2308 | int err; |
| @@ -2280,7 +2313,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) | |||
| 2280 | return err; | 2313 | return err; |
| 2281 | } | 2314 | } |
| 2282 | if (cda[CTA_STATUS]) { | 2315 | if (cda[CTA_STATUS]) { |
| 2283 | err = ctnetlink_change_status(ct, cda); | 2316 | err = ctnetlink_update_status(ct, cda); |
| 2284 | if (err < 0) | 2317 | if (err < 0) |
| 2285 | return err; | 2318 | return err; |
| 2286 | } | 2319 | } |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index a2148d0bc50e..68eda920160e 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
| @@ -279,7 +279,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 279 | struct net *net = sock_net(skb->sk); | 279 | struct net *net = sock_net(skb->sk); |
| 280 | const struct nfnetlink_subsystem *ss; | 280 | const struct nfnetlink_subsystem *ss; |
| 281 | const struct nfnl_callback *nc; | 281 | const struct nfnl_callback *nc; |
| 282 | static LIST_HEAD(err_list); | 282 | LIST_HEAD(err_list); |
| 283 | u32 status; | 283 | u32 status; |
| 284 | int err; | 284 | int err; |
| 285 | 285 | ||
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 26ef70c50e3b..2a6dfe8b74d3 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c | |||
| @@ -463,23 +463,16 @@ static u32 xt_hashlimit_len_to_chunks(u32 len) | |||
| 463 | /* Precision saver. */ | 463 | /* Precision saver. */ |
| 464 | static u64 user2credits(u64 user, int revision) | 464 | static u64 user2credits(u64 user, int revision) |
| 465 | { | 465 | { |
| 466 | if (revision == 1) { | 466 | u64 scale = (revision == 1) ? |
| 467 | /* If multiplying would overflow... */ | 467 | XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2; |
| 468 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1)) | 468 | u64 cpj = (revision == 1) ? |
| 469 | /* Divide first. */ | 469 | CREDITS_PER_JIFFY_v1 : CREDITS_PER_JIFFY; |
| 470 | return div64_u64(user, XT_HASHLIMIT_SCALE) | ||
| 471 | * HZ * CREDITS_PER_JIFFY_v1; | ||
| 472 | |||
| 473 | return div64_u64(user * HZ * CREDITS_PER_JIFFY_v1, | ||
| 474 | XT_HASHLIMIT_SCALE); | ||
| 475 | } else { | ||
| 476 | if (user > 0xFFFFFFFFFFFFFFFFULL / (HZ*CREDITS_PER_JIFFY)) | ||
| 477 | return div64_u64(user, XT_HASHLIMIT_SCALE_v2) | ||
| 478 | * HZ * CREDITS_PER_JIFFY; | ||
| 479 | 470 | ||
| 480 | return div64_u64(user * HZ * CREDITS_PER_JIFFY, | 471 | /* Avoid overflow: divide the constant operands first */ |
| 481 | XT_HASHLIMIT_SCALE_v2); | 472 | if (scale >= HZ * cpj) |
| 482 | } | 473 | return div64_u64(user, div64_u64(scale, HZ * cpj)); |
| 474 | |||
| 475 | return user * div64_u64(HZ * cpj, scale); | ||
| 483 | } | 476 | } |
| 484 | 477 | ||
| 485 | static u32 user2credits_byte(u32 user) | 478 | static u32 user2credits_byte(u32 user) |
