Commit ccaba062 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for your net tree,
they are:

1) Revisit warning logic when not applying default helper assignment.
   Jiri Kosina considers we are breaking existing setups and not warning
   our users accordinly now that automatic helper assignment has been
   turned off by default. So let's make him happy by spotting the warning
   by when we find a helper but we cannot attach, instead of warning on the
   former deprecated behaviour. Patch from Jiri Kosina.

2) Two patches to fix regression in ctnetlink interfaces with
   nfnetlink_queue. Specifically, perform more relaxed in CTA_STATUS
   and do not bail out if CTA_HELP indicates the same helper that we
   already have. Patches from Kevin Cernekee.

3) A couple of bugfixes for ipset via Jozsef Kadlecsik. Due to wrong
   index logic in hash set types and null pointer exception in the
   list:set type.

4) hashlimit bails out with correct userspace parameters due to wrong
   arithmetics in the code that avoids "divide by zero" when
   transforming the userspace timing in milliseconds to token credits.
   Patch from Alban Browaeys.

5) Fix incorrect NFQA_VLAN_MAX definition, patch from
   Ken-ichirou MATSUZAWA.

6) Don't not declare nfnetlink batch error list as static, since this
   may be used by several subsystems at the same time. Patch from
   Liping Zhang.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e65ade77 3ef767e5
...@@ -82,6 +82,10 @@ enum ip_conntrack_status { ...@@ -82,6 +82,10 @@ enum ip_conntrack_status {
IPS_DYING_BIT = 9, IPS_DYING_BIT = 9,
IPS_DYING = (1 << IPS_DYING_BIT), IPS_DYING = (1 << IPS_DYING_BIT),
/* Bits that cannot be altered from userland. */
IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING),
/* Connection has fixed timeout. */ /* Connection has fixed timeout. */
IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT_BIT = 10,
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
......
...@@ -36,7 +36,7 @@ enum nfqnl_vlan_attr { ...@@ -36,7 +36,7 @@ enum nfqnl_vlan_attr {
NFQA_VLAN_TCI, /* __be16 skb htons(vlan_tci) */ NFQA_VLAN_TCI, /* __be16 skb htons(vlan_tci) */
__NFQA_VLAN_MAX, __NFQA_VLAN_MAX,
}; };
#define NFQA_VLAN_MAX (__NFQA_VLAN_MAX + 1) #define NFQA_VLAN_MAX (__NFQA_VLAN_MAX - 1)
enum nfqnl_attr_type { enum nfqnl_attr_type {
NFQA_UNSPEC, NFQA_UNSPEC,
......
...@@ -897,7 +897,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -897,7 +897,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
continue; continue;
data = ahash_data(n, j, dsize); data = ahash_data(n, j, dsize);
memcpy(tmp->value + k * dsize, data, dsize); memcpy(tmp->value + k * dsize, data, dsize);
set_bit(j, tmp->used); set_bit(k, tmp->used);
k++; k++;
} }
tmp->pos = k; tmp->pos = k;
......
...@@ -260,11 +260,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -260,11 +260,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
else else
prev = e; prev = e;
} }
/* Re-add already existing element */
if (n) { /* If before/after is used on an empty set */
if ((d->before > 0 && !next) || if ((d->before > 0 && !next) ||
(d->before < 0 && !prev)) (d->before < 0 && !prev))
return -IPSET_ERR_REF_EXIST; return -IPSET_ERR_REF_EXIST;
/* Re-add already existing element */
if (n) {
if (!flag_exist) if (!flag_exist)
return -IPSET_ERR_EXIST; return -IPSET_ERR_EXIST;
/* Update extensions */ /* Update extensions */
......
...@@ -188,6 +188,26 @@ nf_ct_helper_ext_add(struct nf_conn *ct, ...@@ -188,6 +188,26 @@ nf_ct_helper_ext_add(struct nf_conn *ct,
} }
EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
static struct nf_conntrack_helper *
nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
{
if (!net->ct.sysctl_auto_assign_helper) {
if (net->ct.auto_assign_helper_warned)
return NULL;
if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple))
return NULL;
pr_info("nf_conntrack: default automatic helper assignment "
"has been turned off for security reasons and CT-based "
" firewall rule not found. Use the iptables CT target "
"to attach helpers instead.\n");
net->ct.auto_assign_helper_warned = 1;
return NULL;
}
return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
}
int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
gfp_t flags) gfp_t flags)
{ {
...@@ -213,22 +233,15 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, ...@@ -213,22 +233,15 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
} }
help = nfct_help(ct); help = nfct_help(ct);
if (net->ct.sysctl_auto_assign_helper && helper == NULL) {
helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
if (unlikely(!net->ct.auto_assign_helper_warned && helper)) {
pr_info("nf_conntrack: automatic helper "
"assignment is deprecated and it will "
"be removed soon. Use the iptables CT target "
"to attach helpers instead.\n");
net->ct.auto_assign_helper_warned = true;
}
}
if (helper == NULL) {
helper = nf_ct_lookup_helper(ct, net);
if (helper == NULL) { if (helper == NULL) {
if (help) if (help)
RCU_INIT_POINTER(help->helper, NULL); RCU_INIT_POINTER(help->helper, NULL);
return 0; return 0;
} }
}
if (help == NULL) { if (help == NULL) {
help = nf_ct_helper_ext_add(ct, helper, flags); help = nf_ct_helper_ext_add(ct, helper, flags);
......
...@@ -1478,14 +1478,23 @@ static int ctnetlink_change_helper(struct nf_conn *ct, ...@@ -1478,14 +1478,23 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
struct nlattr *helpinfo = NULL; struct nlattr *helpinfo = NULL;
int err; int err;
/* don't change helper of sibling connections */
if (ct->master)
return -EBUSY;
err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo); err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo);
if (err < 0) if (err < 0)
return err; return err;
/* don't change helper of sibling connections */
if (ct->master) {
/* If we try to change the helper to the same thing twice,
* treat the second attempt as a no-op instead of returning
* an error.
*/
if (help && help->helper &&
!strcmp(help->helper->name, helpname))
return 0;
else
return -EBUSY;
}
if (!strcmp(helpname, "")) { if (!strcmp(helpname, "")) {
if (help && help->helper) { if (help && help->helper) {
/* we had a helper before ... */ /* we had a helper before ... */
...@@ -2269,6 +2278,30 @@ ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct, ...@@ -2269,6 +2278,30 @@ ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct,
return -ENOSPC; return -ENOSPC;
} }
static int
ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[])
{
unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS]));
unsigned long d = ct->status ^ status;
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
/* SEEN_REPLY bit can only be set */
return -EBUSY;
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
/* ASSURED bit can only be set */
return -EBUSY;
/* This check is less strict than ctnetlink_change_status()
* because callers often flip IPS_EXPECTED bits when sending
* an NFQA_CT attribute to the kernel. So ignore the
* unchangeable bits but do not error out.
*/
ct->status = (status & ~IPS_UNCHANGEABLE_MASK) |
(ct->status & IPS_UNCHANGEABLE_MASK);
return 0;
}
static int static int
ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
{ {
...@@ -2280,7 +2313,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) ...@@ -2280,7 +2313,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
return err; return err;
} }
if (cda[CTA_STATUS]) { if (cda[CTA_STATUS]) {
err = ctnetlink_change_status(ct, cda); err = ctnetlink_update_status(ct, cda);
if (err < 0) if (err < 0)
return err; return err;
} }
......
...@@ -279,7 +279,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -279,7 +279,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
const struct nfnetlink_subsystem *ss; const struct nfnetlink_subsystem *ss;
const struct nfnl_callback *nc; const struct nfnl_callback *nc;
static LIST_HEAD(err_list); LIST_HEAD(err_list);
u32 status; u32 status;
int err; int err;
......
...@@ -463,23 +463,16 @@ static u32 xt_hashlimit_len_to_chunks(u32 len) ...@@ -463,23 +463,16 @@ static u32 xt_hashlimit_len_to_chunks(u32 len)
/* Precision saver. */ /* Precision saver. */
static u64 user2credits(u64 user, int revision) static u64 user2credits(u64 user, int revision)
{ {
if (revision == 1) { u64 scale = (revision == 1) ?
/* If multiplying would overflow... */ XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1)) u64 cpj = (revision == 1) ?
/* Divide first. */ CREDITS_PER_JIFFY_v1 : CREDITS_PER_JIFFY;
return div64_u64(user, XT_HASHLIMIT_SCALE)
* HZ * CREDITS_PER_JIFFY_v1;
return div64_u64(user * HZ * CREDITS_PER_JIFFY_v1,
XT_HASHLIMIT_SCALE);
} else {
if (user > 0xFFFFFFFFFFFFFFFFULL / (HZ*CREDITS_PER_JIFFY))
return div64_u64(user, XT_HASHLIMIT_SCALE_v2)
* HZ * CREDITS_PER_JIFFY;
return div64_u64(user * HZ * CREDITS_PER_JIFFY, /* Avoid overflow: divide the constant operands first */
XT_HASHLIMIT_SCALE_v2); if (scale >= HZ * cpj)
} return div64_u64(user, div64_u64(scale, HZ * cpj));
return user * div64_u64(HZ * cpj, scale);
} }
static u32 user2credits_byte(u32 user) static u32 user2credits_byte(u32 user)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment