[ovs-dev] [PATCH] ofproto: Fix use-after-free error when ports disappear.

Ben Pfaff blp at nicira.com
Mon Apr 23 21:08:01 UTC 2012


Pushed to master, branch-1.[23456].

On Mon, Apr 23, 2012 at 10:34:02AM -0700, Justin Pettit wrote:
> Looks good to me.  Thanks.
> 
> --Justin
> 
> 
> On Apr 23, 2012, at 9:16 AM, Ben Pfaff wrote:
> 
> > update_port() can delete the port for which it is called, if the underlying
> > network device has been destroyed, so HMAP_FOR_EACH is unsafe in
> > ofproto_run().
> > 
> > Less obviously, update_port() can delete unrelated ports.  For example,
> > suppose that initially device A is port 1 and device B is port 2.  If
> > update_port("A") runs just after this, then it will ofport_remove() both
> > ports, then ofport_install() A as the new port 2.
> > 
> > So this commit first assembles a list of ports to update, then updates them
> > in a separate loop.
> > 
> > Without this commit, running "ovs-dpctl del-dp" while ovs-vswitchd is
> > running consistently causes a crash for me within a few seconds.
> > 
> > Signed-off-by: Ben Pfaff <blp at nicira.com>
> > ---
> > ofproto/ofproto.c |   18 ++++++++++++++++--
> > 1 files changed, 16 insertions(+), 2 deletions(-)
> > 
> > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> > index f934306..cb46d26 100644
> > --- a/ofproto/ofproto.c
> > +++ b/ofproto/ofproto.c
> > @@ -1027,8 +1027,9 @@ process_port_change(struct ofproto *ofproto, int error, char *devname)
> > int
> > ofproto_run(struct ofproto *p)
> > {
> > +    struct sset changed_netdevs;
> > +    const char *changed_netdev;
> >     struct ofport *ofport;
> > -    char *devname;
> >     int error;
> > 
> >     error = p->ofproto_class->run(p);
> > @@ -1037,18 +1038,31 @@ ofproto_run(struct ofproto *p)
> >     }
> > 
> >     if (p->ofproto_class->port_poll) {
> > +        char *devname;
> > +
> >         while ((error = p->ofproto_class->port_poll(p, &devname)) != EAGAIN) {
> >             process_port_change(p, error, devname);
> >         }
> >     }
> > 
> > +    /* Update OpenFlow port status for any port whose netdev has changed.
> > +     *
> > +     * Refreshing a given 'ofport' can cause an arbitrary ofport to be
> > +     * destroyed, so it's not safe to update ports directly from the
> > +     * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE.  Instead, we
> > +     * need this two-phase approach. */
> > +    sset_init(&changed_netdevs);
> >     HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
> >         unsigned int change_seq = netdev_change_seq(ofport->netdev);
> >         if (ofport->change_seq != change_seq) {
> >             ofport->change_seq = change_seq;
> > -            update_port(p, netdev_get_name(ofport->netdev));
> > +            sset_add(&changed_netdevs, netdev_get_name(ofport->netdev));
> >         }
> >     }
> > +    SSET_FOR_EACH (changed_netdev, &changed_netdevs) {
> > +        update_port(p, changed_netdev);
> > +    }
> > +    sset_destroy(&changed_netdevs);
> > 
> >     switch (p->state) {
> >     case S_OPENFLOW:
> > -- 
> > 1.7.2.5
> > 
> > _______________________________________________
> > dev mailing list
> > dev at openvswitch.org
> > http://openvswitch.org/mailman/listinfo/dev
> 



More information about the dev mailing list