Thanks for the review.  Ordinarily I would spend some time refining the
commit message to better explain, because I like commit messages to be
clear to everyone, but I am feeling a lot of pressure to fix this bug,
so I pushed it as is.

On Thu, May 22, 2014 at 02:24:37PM +1200, Joe Stringer wrote:
> The commit message is a bit confusing to me, I don't see the relationship
> to commit 1340ce0c175. I see it more as a discrepancy between the behaviour
> of dpif_linux_flow_dump_next_may_destroy_keys() and
> dpif_linux_flow_dump_next(). However I agree with the rest of the commit
> message.
> 
> Tested briefly, didn't check it fixes the original bug.
> 
> Acked-by: Joe Stringer <joestrin...@nicira.com>
> 
> 
> On 22 May 2014 11:26, Ben Pfaff <b...@nicira.com> wrote:
> 
> > Commit 1340ce0c175 (ofproto-dpif-upcall: Avoid use-after-free in
> > revalidate() corner cases.) fixed one use-after-free error in revalidate(),
> > but missed one more subtle case, in which dpif_linux_flow_dump_next()
> > attempts to retrieve actions for a flow that didn't have them in the main
> > dump result.  If retrieving those actions fails,
> > dpif_linux_flow_dump_next() goes on to the next flow, and as part of that
> > overwrites the old dumped flows in its buffer.  This is a problem because
> > dpif_linux_flow_dump_next_may_destroy_keys() would have indicated that
> > the old dumped flows would not have been destroyed, which means that the
> > data the caller relied on has gone away.  In the worst case, this causes
> > a segfault and core dump.
> >
> > The best way to fix this problem is the refactoring that has already
> > happened on master in commit ac64794acb85 (dpif: Refactor flow dumping
> > interface to make better sense for batching.)  That is a fairly large
> > change, and not yet well-tested, so it doesn't yet seem suitable for a
> > stable branch.  For now, this commit refines the conditions that
> > dpif_linux_flow_dump_next_may_destroy_keys() uses, so that if the next
> > flow does not include actions it indicates that keys may be destroyed.
> >
> > Thanks to Joe Stringer for suggesting this particular solution.
> >
> > Bug #1249988.
> > Signed-off-by: Ben Pfaff <b...@nicira.com>
> > ---
> >  lib/dpif-linux.c     |   12 ++++++++++--
> >  lib/netlink-socket.c |   13 +++++++++++++
> >  lib/netlink-socket.h |    1 +
> >  3 files changed, 24 insertions(+), 2 deletions(-)
> >
> > diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
> > index abb4b51..4af0607 100644
> > --- a/lib/dpif-linux.c
> > +++ b/lib/dpif-linux.c
> > @@ -1256,8 +1256,16 @@ static bool
> >  dpif_linux_flow_dump_next_may_destroy_keys(void *state_)
> >  {
> >      struct dpif_linux_flow_state *state = state_;
> > -
> > -    return ofpbuf_size(&state->buffer) ? false : true;
> > +    struct dpif_linux_flow flow;
> > +    struct ofpbuf nlmsg;
> > +
> > +    /* Check whether there's a flow remaining in the buffer that includes
> > +     * actions.  (If it does not include actions, then we could end up
> > +     * destroying keys previously returned trying to retrieve its actions
> > +     * fails.) */
> > +    return (!nl_dump_peek(&nlmsg, &state->buffer)
> > +            || dpif_linux_flow_from_ofpbuf(&flow, &nlmsg)
> > +            || !flow.actions);
> >  }
> >
> >  static int
> > diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c
> > index e4cc4ad..ef476f2 100644
> > --- a/lib/netlink-socket.c
> > +++ b/lib/netlink-socket.c
> > @@ -797,6 +797,19 @@ exit:
> >      return !error;
> >  }
> >
> > +/* Attempts to look ahead in 'buffer' to obtain the next reply that will
> > be
> > + * returned by nl_dump_next().  Returns true if successful, in which case
> > + * 'reply' will be initialize to the message that will be obtained by the
> > next
> > + * call to nl_dump_next(), or false on failure.  Failure doesn't
> > necessarily
> > + * mean that the nl_dump_next() will fail, only that it needs to obtain a
> > new
> > + * block of dump results from the kernel. */
> > +bool
> > +nl_dump_peek(struct ofpbuf *reply, struct ofpbuf *buffer)
> > +{
> > +    struct ofpbuf tmp = *buffer;
> > +    return nl_msg_next(&tmp, reply);
> > +}
> > +
> >  /* Completes Netlink dump operation 'dump', which must have been
> > initialized
> >   * with nl_dump_start().  Returns 0 if the dump operation was error-free,
> >   * otherwise a positive errno value describing the problem. */
> > diff --git a/lib/netlink-socket.h b/lib/netlink-socket.h
> > index dd32409..1f06b97 100644
> > --- a/lib/netlink-socket.h
> > +++ b/lib/netlink-socket.h
> > @@ -119,6 +119,7 @@ struct nl_dump {
> >  void nl_dump_start(struct nl_dump *, int protocol,
> >                     const struct ofpbuf *request);
> >  bool nl_dump_next(struct nl_dump *, struct ofpbuf *reply, struct ofpbuf
> > *buf);
> > +bool nl_dump_peek(struct ofpbuf *reply, struct ofpbuf *buf);
> >  int nl_dump_done(struct nl_dump *);
> >
> >  /* Miscellaneous */
> > --
> > 1.7.10.4
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > http://openvswitch.org/mailman/listinfo/dev
> >
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to