From: Ben Pfaff Date: Wed, 4 Sep 2013 19:38:12 +0000 (-0700) Subject: ofproto-dpif: Fix use-after-free deleting a bridge with active traffic. X-Git-Tag: v2.0~93 X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Fovs.git;a=commitdiff_plain;h=52460c160bc617af0537ba5ad966b5006d316d91 ofproto-dpif: Fix use-after-free deleting a bridge with active traffic. When a bridge that has active traffic is deleted, the bridge's ofproto can be referenced by in-flight "flow_miss"es. This commit fixes the problem by destroying "flow_miss"es that reference the ofproto that is being deleted. I found the problem by adding and removing a bridge that had active traffic (via hping3) while running under valgrind. Signed-off-by: Ben Pfaff Acked-by: Ethan Jackson --- diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 22cdf1b8a..3294d3b48 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -347,6 +347,37 @@ flow_miss_batch_destroy(struct flow_miss_batch *fmb) free(fmb); } +/* Discards any flow miss batches queued up in 'udpif' for 'ofproto' (because + * 'ofproto' is being destroyed). + * + * 'ofproto''s xports must already have been removed, otherwise new flow miss + * batches could still end up getting queued. */ +void +flow_miss_batch_ofproto_destroyed(struct udpif *udpif, + const struct ofproto_dpif *ofproto) +{ + struct flow_miss_batch *fmb, *next_fmb; + + ovs_mutex_lock(&udpif->fmb_mutex); + LIST_FOR_EACH_SAFE (fmb, next_fmb, list_node, &udpif->fmbs) { + struct flow_miss *miss, *next_miss; + + HMAP_FOR_EACH_SAFE (miss, next_miss, hmap_node, &fmb->misses) { + if (miss->ofproto == ofproto) { + hmap_remove(&fmb->misses, &miss->hmap_node); + miss_destroy(miss); + } + } + + if (hmap_is_empty(&fmb->misses)) { + list_remove(&fmb->list_node); + flow_miss_batch_destroy(fmb); + udpif->n_fmbs--; + } + } + ovs_mutex_unlock(&udpif->fmb_mutex); +} + /* Retreives the next drop key which ofproto-dpif needs to process. The caller * is responsible for destroying it with drop_key_destroy(). */ struct drop_key * diff --git a/ofproto/ofproto-dpif-upcall.h b/ofproto/ofproto-dpif-upcall.h index f597672b9..8e8264e2e 100644 --- a/ofproto/ofproto-dpif-upcall.h +++ b/ofproto/ofproto-dpif-upcall.h @@ -109,6 +109,9 @@ struct flow_miss_batch { struct flow_miss_batch *flow_miss_batch_next(struct udpif *); void flow_miss_batch_destroy(struct flow_miss_batch *); + +void flow_miss_batch_ofproto_destroyed(struct udpif *, + const struct ofproto_dpif *); /* Drop keys are odp flow keys which have drop flows installed in the kernel. * These are datapath flows which have no associated ofproto, if they did we diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 7d6640994..f20fb525e 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1437,6 +1437,8 @@ destruct(struct ofproto *ofproto_) xlate_remove_ofproto(ofproto); ovs_rwlock_unlock(&xlate_rwlock); + flow_miss_batch_ofproto_destroyed(ofproto->backer->udpif, ofproto); + hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node); complete_operations(ofproto);