[RFC PATCH 13/23] vinyl: fix potential use-after-free in vy_read_view_merge

Vladimir Davydov vdavydov.dev at gmail.com
Sun Jul 8 19:48:44 MSK 2018


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




More information about the Tarantool-patches mailing list