Commit 9ea4894b authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

Merge branch 'master' of git://blackhole.kfki.hu/nf

Jozsef Kadlecsik says:

====================
ipset patches for nf

The first one is larger than usual, but the issue could not be solved simpler.
Also, it's a resend of the patch I submitted a few days ago, with a one line
fix on top of that: the size of the comment extensions was not taken into
account at reporting the full size of the set.

- Fix "INFO: rcu detected stall in hash_xxx" reports of syzbot
  by introducing region locking and using workqueue instead of timer based
  gc of timed out entries in hash types of sets in ipset.
- Fix the forceadd evaluation path - the bug was also uncovered by the syzbot.
====================
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parents d0820556 8af1c6fb
...@@ -121,6 +121,7 @@ struct ip_set_ext { ...@@ -121,6 +121,7 @@ struct ip_set_ext {
u32 timeout; u32 timeout;
u8 packets_op; u8 packets_op;
u8 bytes_op; u8 bytes_op;
bool target;
}; };
struct ip_set; struct ip_set;
...@@ -187,6 +188,14 @@ struct ip_set_type_variant { ...@@ -187,6 +188,14 @@ struct ip_set_type_variant {
/* Return true if "b" set is the same as "a" /* Return true if "b" set is the same as "a"
* according to the create set parameters */ * according to the create set parameters */
bool (*same_set)(const struct ip_set *a, const struct ip_set *b); bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
/* Region-locking is used */
bool region_lock;
};
struct ip_set_region {
spinlock_t lock; /* Region lock */
size_t ext_size; /* Size of the dynamic extensions */
u32 elements; /* Number of elements vs timeout */
}; };
/* The core set type structure */ /* The core set type structure */
...@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo, ...@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
} }
#define IP_SET_INIT_KEXT(skb, opt, set) \ #define IP_SET_INIT_KEXT(skb, opt, set) \
{ .bytes = (skb)->len, .packets = 1, \ { .bytes = (skb)->len, .packets = 1, .target = true,\
.timeout = ip_set_adt_opt_timeout(opt, set) } .timeout = ip_set_adt_opt_timeout(opt, set) }
#define IP_SET_INIT_UEXT(set) \ #define IP_SET_INIT_UEXT(set) \
......
...@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index) ...@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
return set; return set;
} }
static inline void
ip_set_lock(struct ip_set *set)
{
if (!set->variant->region_lock)
spin_lock_bh(&set->lock);
}
static inline void
ip_set_unlock(struct ip_set *set)
{
if (!set->variant->region_lock)
spin_unlock_bh(&set->lock);
}
int int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt) const struct xt_action_param *par, struct ip_set_adt_opt *opt)
...@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ...@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
/* Type requests element to be completed */ /* Type requests element to be completed */
pr_debug("element must be completed, ADD is triggered\n"); pr_debug("element must be completed, ADD is triggered\n");
spin_lock_bh(&set->lock); ip_set_lock(set);
set->variant->kadt(set, skb, par, IPSET_ADD, opt); set->variant->kadt(set, skb, par, IPSET_ADD, opt);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
ret = 1; ret = 1;
} else { } else {
/* --return-nomatch: invert matched element */ /* --return-nomatch: invert matched element */
...@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, ...@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
!(opt->family == set->family || set->family == NFPROTO_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return -IPSET_ERR_TYPE_MISMATCH; return -IPSET_ERR_TYPE_MISMATCH;
spin_lock_bh(&set->lock); ip_set_lock(set);
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt); ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
return ret; return ret;
} }
...@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, ...@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
!(opt->family == set->family || set->family == NFPROTO_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return -IPSET_ERR_TYPE_MISMATCH; return -IPSET_ERR_TYPE_MISMATCH;
spin_lock_bh(&set->lock); ip_set_lock(set);
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt); ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
return ret; return ret;
} }
...@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set) ...@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
{ {
pr_debug("set: %s\n", set->name); pr_debug("set: %s\n", set->name);
spin_lock_bh(&set->lock); ip_set_lock(set);
set->variant->flush(set); set->variant->flush(set);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
} }
static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
...@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, ...@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
bool eexist = flags & IPSET_FLAG_EXIST, retried = false; bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
do { do {
spin_lock_bh(&set->lock); ip_set_lock(set);
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried); ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
retried = true; retried = true;
} while (ret == -EAGAIN && } while (ret == -EAGAIN &&
set->variant->resize && set->variant->resize &&
......
This diff is collapsed.
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