@@ -249,11 +249,11 @@ cls_rule_set_conjunctions(struct cls_rule *cr,
unsigned int old_n = old ? old->n : 0;
if (old_n != n || (n && memcmp(old_conj, conj, n * sizeof *conj))) {
+ ovsrcu_set(&match->conj_set,
+ cls_conjunction_set_alloc(match, conj, n));
if (old) {
ovsrcu_postpone(free, old);
}
- ovsrcu_set(&match->conj_set,
- cls_conjunction_set_alloc(match, conj, n));
}
}
@@ -119,9 +119,9 @@
* change_flow(struct flow *new_flow)
* {
* ovs_mutex_lock(&mutex);
+ * ovsrcu_set(&flowp, new_flow);
* ovsrcu_postpone(free,
* ovsrcu_get_protected(struct flow *, &flowp));
- * ovsrcu_set(&flowp, new_flow);
* ovs_mutex_unlock(&mutex);
* }
*
@@ -67,10 +67,11 @@ pvector_init(struct pvector *pvec)
void
pvector_destroy(struct pvector *pvec)
{
+ struct pvector_impl *old = pvector_impl_get(pvec);
free(pvec->temp);
pvec->temp = NULL;
- ovsrcu_postpone(free, pvector_impl_get(pvec));
ovsrcu_set(&pvec->impl, NULL); /* Poison. */
+ ovsrcu_postpone(free, old);
}
/* Iterators for callers that need the 'index' afterward. */
@@ -205,11 +206,11 @@ pvector_change_priority(struct pvector *pvec, void *ptr, int priority)
/* Make the modified pvector available for iteration. */
void pvector_publish__(struct pvector *pvec)
{
- struct pvector_impl *temp = pvec->temp;
-
+ struct pvector_impl *new = pvec->temp;
+ struct pvector_impl *old = vsrcu_get_protected(struct pvector_impl *,
+ &pvec->impl);
pvec->temp = NULL;
- pvector_impl_sort(temp); /* Also removes gaps. */
- ovsrcu_postpone(free, ovsrcu_get_protected(struct pvector_impl *,
- &pvec->impl));
- ovsrcu_set(&pvec->impl, temp);
+ pvector_impl_sort(new); /* Also removes gaps. */
+ ovsrcu_set(&pvec->impl, new);
+ ovsrcu_postpone(free, old);
}
@@ -276,9 +276,9 @@ mirror_set(struct mbridge *mbridge, void *aux, const char *name,
hmapx_destroy(&dsts_map);
if (vlans || src_vlans) {
+ unsigned long *new_vlans = vlan_bitmap_clone(src_vlans);
+ ovsrcu_set(&mirror->vlans, new_vlans);
ovsrcu_postpone(free, vlans);
- vlans = vlan_bitmap_clone(src_vlans);
- ovsrcu_set(&mirror->vlans, vlans);
}
mirror->out = out;
@@ -1658,11 +1658,10 @@ ukey_set_actions(struct udpif_key *ukey, const struct ofpbuf *actions)
struct ofpbuf *old_actions = ovsrcu_get_protected(struct ofpbuf *,
&ukey->actions);
+ ovsrcu_set(&ukey->actions, ofpbuf_clone(actions));
if (old_actions) {
ovsrcu_postpone(ofpbuf_delete, old_actions);
}
-
- ovsrcu_set(&ukey->actions, ofpbuf_clone(actions));
}
static struct udpif_key *
We should update rcu pointer first then use ovsrcu_postpone to free otherwise maybe cause use-after-free. e.g, thead are two threads, A and B: 1. thread A call ovsrcu_postpone and flush cbset, have not call ovsrcu_quiesce 2. thread rcu wait all threads call ovsrcu_quiesce 3. thread B call ovsrcu_quiesce 4. thread B next round get the old pointer 5. thrad A call ovsrcu_quiesce 6. thread rcu free old pointer 7. thread B use-after-free Signed-off-by: Haifeng Lin <haifeng.lin@huawei.com> --- lib/classifier.c | 4 ++-- lib/ovs-rcu.h | 2 +- lib/pvector.c | 15 ++++++++------- ofproto/ofproto-dpif-mirror.c | 4 ++-- ofproto/ofproto-dpif-upcall.c | 3 +-- 5 files changed, 14 insertions(+), 14 deletions(-)