[ovs-dev] [PATCH v4] classifier: Prevent tries vs n_tries race leading to NULL dereference.
Ilya Maximets
i.maximets at ovn.org
Wed May 27 22:28:38 UTC 2020
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.tsukata at 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.
More information about the dev
mailing list