From ddf11d8c60b0d46dd25520d388243b508d6e9016 Mon Sep 17 00:00:00 2001
From: Kent Overstreet <kent.overstreet@gmail.com>
Date: Sun, 27 Feb 2022 11:34:21 -0500
Subject: [PATCH] bcachefs: Fix a use after free

This fixes a regression from "bcachefs: Stash a copy of key being
overwritten in btree_insert_entry". In btree_key_can_insert_cached(), we
may reallocate the key cache key, invalidating pointers previously
returned by peek() - fix it by issuing a transaction restart.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
---
 fs/bcachefs/btree_update_leaf.c | 13 ++++++++++++-
 fs/bcachefs/trace.h             |  8 ++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/fs/bcachefs/btree_update_leaf.c b/fs/bcachefs/btree_update_leaf.c
index dc4dfcda8f21..42ee54cf390d 100644
--- a/fs/bcachefs/btree_update_leaf.c
+++ b/fs/bcachefs/btree_update_leaf.c
@@ -382,7 +382,18 @@ btree_key_can_insert_cached(struct btree_trans *trans,
 
 	ck->u64s	= new_u64s;
 	ck->k		= new_k;
-	return BTREE_INSERT_OK;
+	/*
+	 * Keys returned by peek() are no longer valid pointers, so we need a
+	 * transaction restart:
+	 */
+	trace_trans_restart_key_cache_key_realloced(trans->fn, _RET_IP_,
+					     path->btree_id, &path->pos);
+	/*
+	 * Not using btree_trans_restart() because we can't unlock here, we have
+	 * write locks held:
+	 */
+	trans->restarted = true;
+	return -EINTR;
 }
 
 static inline void do_btree_insert_one(struct btree_trans *trans,
diff --git a/fs/bcachefs/trace.h b/fs/bcachefs/trace.h
index b35022dc66c2..af3785254c71 100644
--- a/fs/bcachefs/trace.h
+++ b/fs/bcachefs/trace.h
@@ -918,6 +918,14 @@ TRACE_EVENT(trans_restart_mem_realloced,
 		  __entry->bytes)
 );
 
+DEFINE_EVENT(transaction_restart_iter,	trans_restart_key_cache_key_realloced,
+	TP_PROTO(const char *trans_fn,
+		 unsigned long caller_ip,
+		 enum btree_id btree_id,
+		 struct bpos *pos),
+	TP_ARGS(trans_fn, caller_ip, btree_id, pos)
+);
+
 #endif /* _TRACE_BCACHEFS_H */
 
 /* This part must be outside protection */
-- 
2.30.9