[ovs-dev] [PATCH] flow: Avoid unsafe comparison of minimasks.

Dumitru Ceara dceara at redhat.com
Wed Jul 17 19:17:37 UTC 2019


On Wed, Jul 17, 2019 at 7:55 PM Ben Pfaff <blp at ovn.org> wrote:
>
> The following, run inside the OVS sandbox, caused OVS to abort when
> Address Sanitizer was used:
>
>     ovs-vsctl add-br br-int
>     ovs-ofctl add-flow br-int "table=0,cookie=0x1234,priority=10000,icmp,actions=drop"
>     ovs-ofctl --strict del-flows br-int "table=0,cookie=0x1234/-1,priority=10000"
>
> Sample report from Address Sanitizer:
>
> ==3029==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000043260 at pc 0x7f6b09c2459b bp 0x7ffcb67e7540 sp 0x7ffcb67e6cf0
> READ of size 40 at 0x603000043260 thread T0
>     #0 0x7f6b09c2459a  (/lib/x86_64-linux-gnu/libasan.so.5+0xb859a)
>     #1 0x565110a748a5 in minimask_equal ../lib/flow.c:3510
>     #2 0x565110a9ea41 in minimatch_equal ../lib/match.c:1821
>     #3 0x56511091e864 in collect_rules_strict ../ofproto/ofproto.c:4516
>     #4 0x56511093d526 in delete_flow_start_strict ../ofproto/ofproto.c:5959
>     #5 0x56511093d526 in ofproto_flow_mod_start ../ofproto/ofproto.c:7949
>     #6 0x56511093d77b in handle_flow_mod__ ../ofproto/ofproto.c:6122
>     #7 0x56511093db71 in handle_flow_mod ../ofproto/ofproto.c:6099
>     #8 0x5651109407f6 in handle_single_part_openflow ../ofproto/ofproto.c:8406
>     #9 0x5651109407f6 in handle_openflow ../ofproto/ofproto.c:8587
>     #10 0x5651109e40da in ofconn_run ../ofproto/connmgr.c:1318
>     #11 0x5651109e40da in connmgr_run ../ofproto/connmgr.c:355
>     #12 0x56511092b129 in ofproto_run ../ofproto/ofproto.c:1826
>     #13 0x5651108f23cd in bridge_run__ ../vswitchd/bridge.c:2965
>     #14 0x565110904887 in bridge_run ../vswitchd/bridge.c:3023
>     #15 0x5651108e659c in main ../vswitchd/ovs-vswitchd.c:127
>     #16 0x7f6b093b709a in __libc_start_main ../csu/libc-start.c:308
>     #17 0x5651108e9009 in _start (/home/blp/nicira/ovs/_build/vswitchd/ovs-vswitchd+0x11d009)
>
> This fixes the problem, which although largely theoretical could crop up
> with odd implementations of memcmp(), perhaps ones optimized in various
> "clever" ways.  All in all, it seems best to avoid the theoretical problem.
>
> Signed-off-by: Ben Pfaff <blp at ovn.org>

Cool! Looks good (and interesting) to me

Acked-by: Dumitru Ceara <dceara at redhat.com>

> ---
>  lib/flow.c | 19 ++++++++++++++++---
>  1 file changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/lib/flow.c b/lib/flow.c
> index 95da7d4b1803..e54fd2e522e6 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017, 2019 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -3506,8 +3506,21 @@ minimask_expand(const struct minimask *mask, struct flow_wildcards *wc)
>  bool
>  minimask_equal(const struct minimask *a, const struct minimask *b)
>  {
> -    return !memcmp(a, b, sizeof *a
> -                   + MINIFLOW_VALUES_SIZE(miniflow_n_values(&a->masks)));
> +    /* At first glance, it might seem that this can be reasonably optimized
> +     * into a single memcmp() for the total size of the region.  Such an
> +     * optimization will work OK with most implementations of memcmp() that
> +     * proceed from the start of the regions to be compared to the end in
> +     * reasonably sized chunks.  However, memcmp() is not required to be
> +     * implemented that way, and an implementation that, for example, compares
> +     * all of the bytes in both regions without early exit when it finds a
> +     * difference, or one that compares, say, 64 bytes at a time, could access
> +     * an unmapped region of memory if minimasks 'a' and 'b' have different
> +     * lengths.  By first checking that the maps are the same with the first
> +     * memcmp(), we verify that 'a' and 'b' have the same length and therefore
> +     * ensure that the second memcmp() is safe. */
> +    return (!memcmp(a, b, sizeof *a)
> +            && !memcmp(a + 1, b + 1,
> +                       MINIFLOW_VALUES_SIZE(miniflow_n_values(&a->masks))));
>  }
>
>  /* Returns true if at least one bit matched by 'b' is wildcarded by 'a',
> --
> 2.20.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev


More information about the dev mailing list