Hello Ilya

> On May 28, 2020, at 7:28, Ilya Maximets <i.maxim...@ovn.org> wrote:
> 
> On 5/27/20 4:13 AM, Eiichi Tsukata wrote:
>> Currently classifier tries and n_tries can be updated not atomically,
>> there is a race condition which can lead to NULL dereference.
>> The race can happen when main thread updates a classifier tries and
>> n_tries in classifier_set_prefix_fields() and at the same time revalidator
>> or handler thread try to lookup them in classifier_lookup__(). Such race
>> can be triggered when user changes prefixes of flow_table.
>> 
>> Race(user changes flow_table prefixes: ip_dst,ip_src => none):
>> 
>>  [main thread]             [revalidator/handler thread]
>>  ===========================================================
>>                            /* cls->n_tries == 2 */
>>                            for (int i = 0; i < cls->n_tries; i++) {
>>  trie_init(cls, i, NULL);
>>  /* n_tries == 0 */
>>  cls->n_tries = n_tries;
>>                            /* cls->tries[i]->feild is NULL */
>>                            trie_ctx_init(&trie_ctx[i],&cls->tries[i]);
>>                            /* trie->field is NULL */
>>                            ctx->be32ofs = trie->field->flow_be32ofs;
>> 
>> To prevent the race, instead of re-introducing internal mutex
>> implemented in the commit fccd7c092e09 ("classifier: Remove internal
>> mutex."), this patch makes trie field RCU protected and checks it after
>> read.
>> 
>> Fixes: fccd7c092e09 ("classifier: Remove internal mutex.")
>> Signed-off-by: Eiichi Tsukata <eiichi.tsuk...@nutanix.com>
>> ---
> 
> Patch looks good in general, but I'd suggest following incremental change:
> 
> diff --git a/lib/classifier.c b/lib/classifier.c
> index 00e87012c..f2c3497c2 100644
> --- a/lib/classifier.c
> +++ b/lib/classifier.c
> @@ -1577,16 +1577,17 @@ check_tries(struct trie_ctx trie_ctx[CLS_MAX_TRIES], 
> unsigned int n_tries,
>      * fields using the prefix tries.  The trie checks are done only as
>      * needed to avoid folding in additional bits to the wildcards mask. */
>     for (j = 0; j < n_tries; j++) {
> -        /* Is the trie field relevant for this subtable, and
> -           is the trie field within the current range of fields? */
> +        /* Is the trie field relevant for this subtable? */
>         if (field_plen[j]) {
> +            struct trie_ctx *ctx = &trie_ctx[j];
>             const struct mf_field *ctx_field
> -                = ovsrcu_get(struct mf_field *, &trie_ctx[j].trie->field);
> +                = ovsrcu_get(struct mf_field *, &ctx->trie->field);
> +
> +            /* Is the trie field within the current range of fields? */
>             if (!ctx_field
>                 || !flowmap_is_set(&range_map, ctx_field->flow_be32ofs / 2)) {
>                 continue;
>             }
> -            struct trie_ctx *ctx = &trie_ctx[j];
> 
>             /* On-demand trie lookup. */
>             if (!ctx->lookup_done) {
> ---
> 
> What do you think?
> 
> If  you're ok with it, I could just squash above diff into your patch before
> applying.
> 
> Best regards, Ilya Maximets.


Thanks for your suggestion. I think your diff looks pretty nice and makes codes 
easier to understand.
I’m glad if you could squash it.

Best regards,

Eiichi

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to