On 11/30/20 8:45 PM, Han Zhou wrote:
>
>
> On Mon, Nov 30, 2020 at 8:41 AM Dumitru Ceara <[email protected]
> <mailto:[email protected]>> wrote:
>>
>> It's possible that the IDL client processes multiple jsonrpc updates
>> in a single ovsdb_idl_run().
>>
>> Considering the following updates processed in a single IDL run:
>> 1. Update row R1 from table A while R1 is also referenced by row R2 from
>> table B:
>> - this adds R1 to table A's track_list.
>> 2. Delete row R1 from table A while R1 is also referenced by row R2 from
>> table B:
>> - because row R2 still refers to row R1, this will create an orphan
>> R1.
>> - at this point R1 is still in table A's hmap.
>>
>> When the IDL client calls ovsdb_idl_track_clear() after it has finished
>> processing the tracked changes, row R1 gets freed leaving a dangling
>> pointer in table A's hmap.
>>
>> To fix this we don't free rows in ovsdb_idl_track_clear() if they are
>> orphan and still referenced by other rows, i.e., the row's 'dst_arcs'
>> list is not empty. Later, when all arc sources (e.g., R2) are
>> deleted, the orphan R1 will be cleaned up as well.
>>
>> The only exception is when the whole contents of the IDL are flushed,
>> in ovsdb_idl_db_clear(), in which case it's safe to free all rows.
>>
>> Reported-by: Ilya Maximets <[email protected] <mailto:[email protected]>>
>> Fixes: 932104f483ef ("ovsdb-idl: Add support for change tracking.")
>> Signed-off-by: Dumitru Ceara <[email protected] <mailto:[email protected]>>
>> ---
>> lib/ovsdb-idl.c | 21 ++++++++++++++++-----
>> 1 file changed, 16 insertions(+), 5 deletions(-)
>>
>> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
>> index e0c9833..0841a2e 100644
>> --- a/lib/ovsdb-idl.c
>> +++ b/lib/ovsdb-idl.c
>> @@ -221,7 +221,7 @@ struct ovsdb_idl_db {
>> struct uuid last_id;
>> };
>>
>> -static void ovsdb_idl_db_track_clear(struct ovsdb_idl_db *);
>> +static void ovsdb_idl_db_track_clear(struct ovsdb_idl_db *, bool flush_all);
>> static void ovsdb_idl_db_add_column(struct ovsdb_idl_db *,
>> const struct ovsdb_idl_column *);
>> static void ovsdb_idl_db_omit(struct ovsdb_idl_db *,
>> @@ -660,7 +660,7 @@ ovsdb_idl_db_clear(struct ovsdb_idl_db *db)
>> ovsdb_idl_row_destroy_postprocess(db);
>>
>> db->cond_seqno = 0;
>> - ovsdb_idl_db_track_clear(db);
>> + ovsdb_idl_db_track_clear(db, true);
>>
>> if (changed) {
>> db->change_seqno++;
>> @@ -1955,7 +1955,7 @@ ovsdb_idl_track_is_updated(const struct ovsdb_idl_row
>> *row,
>> * loop when it is ready to do ovsdb_idl_run() again.
>> */
>> static void
>> -ovsdb_idl_db_track_clear(struct ovsdb_idl_db *db)
>> +ovsdb_idl_db_track_clear(struct ovsdb_idl_db *db, bool flush_all)
>> {
>> size_t i;
>>
>> @@ -1989,7 +1989,18 @@ ovsdb_idl_db_track_clear(struct ovsdb_idl_db *db)
>> free(row->tracked_old_datum);
>> row->tracked_old_datum = NULL;
>> }
>> - free(row);
>> +
>> + /* Rows that were reused as orphan after being processed
>> + * for deletion are still in the table hmap and will be
>> + * cleaned up when their src arcs are removed.
>> + *
>> + * The exception is when 'destroy' is explicitly set to
>> + * 'true' which usually happens when the complete IDL
>> + * contents are being flushed.
>> + */
>> + if (flush_all || ovs_list_is_empty(&row->dst_arcs)) {
>> + free(row);
>> + }
>
> Here is a problem. The row R1 is now unparsed and datum freed. However, when
> R2 is deleted, R1 will be pushed to the tracked change list again and when
> the user examines it in tracked changes and accesses the old data, it will
> crash.
It is an ophan row and, also, tracked_old_datum already freed,
so it should not be iterable. See:
f0d23f67954c ("ovsdb-idl: Fix iteration over tracked rows with no actual data.")
>
>> }
>> }
>> }
>> @@ -2004,7 +2015,7 @@ ovsdb_idl_db_track_clear(struct ovsdb_idl_db *db)
>> void
>> ovsdb_idl_track_clear(struct ovsdb_idl *idl)
>> {
>> - ovsdb_idl_db_track_clear(&idl->data);
>> + ovsdb_idl_db_track_clear(&idl->data, false);
>> }
>>
>> static void
>>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev