From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladimir Davydov Subject: [RFC PATCH 13/23] vinyl: fix potential use-after-free in vy_read_view_merge Date: Sun, 8 Jul 2018 19:48:44 +0300 Message-Id: In-Reply-To: In-Reply-To: References: To: kostja@tarantool.org Cc: tarantool-patches@freelists.org List-ID: If is_first_insert flag is set and vy_stmt_type(rv->tuple) equals IPROTO_DELETE, we free rv->tuple, but then we dereference it via an on-stack variable to check if we need to turn a REPLACE into an INSERT or vice versa. Fix this. --- src/box/vy_write_iterator.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/box/vy_write_iterator.c b/src/box/vy_write_iterator.c index 7d2ec955..4e758be8 100644 --- a/src/box/vy_write_iterator.c +++ b/src/box/vy_write_iterator.c @@ -792,8 +792,7 @@ vy_read_view_merge(struct vy_write_iterator *stream, struct tuple *hint, /* Not the first statement. */ return 0; } - struct tuple *tuple = rv->tuple; - if (is_first_insert && vy_stmt_type(tuple) == IPROTO_DELETE) { + if (is_first_insert && vy_stmt_type(rv->tuple) == IPROTO_DELETE) { /* * Optimization 6: discard the first DELETE if * the oldest statement for the current key among @@ -801,11 +800,12 @@ vy_read_view_merge(struct vy_write_iterator *stream, struct tuple *hint, * statements for this key in older runs or the * last statement is a DELETE. */ - vy_stmt_unref_if_possible(tuple); + vy_stmt_unref_if_possible(rv->tuple); rv->tuple = NULL; - } - if ((is_first_insert && vy_stmt_type(tuple) == IPROTO_REPLACE) || - (!is_first_insert && vy_stmt_type(tuple) == IPROTO_INSERT)) { + } else if ((is_first_insert && + vy_stmt_type(rv->tuple) == IPROTO_REPLACE) || + (!is_first_insert && + vy_stmt_type(rv->tuple) == IPROTO_INSERT)) { /* * If the oldest statement among all sources is an * INSERT, convert the first REPLACE to an INSERT @@ -818,14 +818,14 @@ vy_read_view_merge(struct vy_write_iterator *stream, struct tuple *hint, * compaction. */ uint32_t size; - const char *data = tuple_data_range(tuple, &size); + const char *data = tuple_data_range(rv->tuple, &size); struct tuple *copy = is_first_insert ? vy_stmt_new_insert(stream->format, data, data + size) : vy_stmt_new_replace(stream->format, data, data + size); if (copy == NULL) return -1; - vy_stmt_set_lsn(copy, vy_stmt_lsn(tuple)); - vy_stmt_unref_if_possible(tuple); + vy_stmt_set_lsn(copy, vy_stmt_lsn(rv->tuple)); + vy_stmt_unref_if_possible(rv->tuple); rv->tuple = copy; } return 0; -- 2.11.0