mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
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: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
commit
9ea4894ba4
@ -121,6 +121,7 @@ struct ip_set_ext {
|
||||
u32 timeout;
|
||||
u8 packets_op;
|
||||
u8 bytes_op;
|
||||
bool target;
|
||||
};
|
||||
|
||||
struct ip_set;
|
||||
@ -187,6 +188,14 @@ struct ip_set_type_variant {
|
||||
/* Return true if "b" set is the same as "a"
|
||||
* according to the create set parameters */
|
||||
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 */
|
||||
@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
|
||||
}
|
||||
|
||||
#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) }
|
||||
|
||||
#define IP_SET_INIT_UEXT(set) \
|
||||
|
@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
|
||||
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
|
||||
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)
|
||||
@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
if (ret == -EAGAIN) {
|
||||
/* Type requests element to be completed */
|
||||
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);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
ret = 1;
|
||||
} else {
|
||||
/* --return-nomatch: invert matched element */
|
||||
@ -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))
|
||||
return -IPSET_ERR_TYPE_MISMATCH;
|
||||
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(set);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -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))
|
||||
return -IPSET_ERR_TYPE_MISMATCH;
|
||||
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(set);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
|
||||
{
|
||||
pr_debug("set: %s\n", set->name);
|
||||
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(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,
|
||||
@ -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;
|
||||
|
||||
do {
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(set);
|
||||
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
retried = true;
|
||||
} while (ret == -EAGAIN &&
|
||||
set->variant->resize &&
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user