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