Commit 58caa786 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Fix UAFs of btree_insert_entry array



The btree paths array is now dynamically resizable - and as well the
btree_insert_entries array, as it needs to be the same size.

The merge path (and interior update path) allocates new btree paths,
thus can trigger a resize; thus we need to not retain direct pointers
after invoking merge; similarly when running btree node triggers.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 2b3e79fe
Loading
Loading
Loading
Loading
+14 −13
Original line number Diff line number Diff line
@@ -499,9 +499,8 @@ static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_
}

static int run_btree_triggers(struct btree_trans *trans, enum btree_id btree_id,
			      struct btree_insert_entry *btree_id_start)
			      unsigned btree_id_start)
{
	struct btree_insert_entry *i;
	bool trans_trigger_run;
	int ret, overwrite;

@@ -514,13 +513,13 @@ static int run_btree_triggers(struct btree_trans *trans, enum btree_id btree_id,
		do {
			trans_trigger_run = false;

			for (i = btree_id_start;
			     i < trans->updates + trans->nr_updates && i->btree_id <= btree_id;
			for (unsigned i = btree_id_start;
			     i < trans->nr_updates && trans->updates[i].btree_id <= btree_id;
			     i++) {
				if (i->btree_id != btree_id)
				if (trans->updates[i].btree_id != btree_id)
					continue;

				ret = run_one_trans_trigger(trans, i, overwrite);
				ret = run_one_trans_trigger(trans, trans->updates + i, overwrite);
				if (ret < 0)
					return ret;
				if (ret)
@@ -534,8 +533,7 @@ static int run_btree_triggers(struct btree_trans *trans, enum btree_id btree_id,

static int bch2_trans_commit_run_triggers(struct btree_trans *trans)
{
	struct btree_insert_entry *btree_id_start = trans->updates;
	unsigned btree_id = 0;
	unsigned btree_id = 0, btree_id_start = 0;
	int ret = 0;

	/*
@@ -549,8 +547,8 @@ static int bch2_trans_commit_run_triggers(struct btree_trans *trans)
		if (btree_id == BTREE_ID_alloc)
			continue;

		while (btree_id_start < trans->updates + trans->nr_updates &&
		       btree_id_start->btree_id < btree_id)
		while (btree_id_start < trans->nr_updates &&
		       trans->updates[btree_id_start].btree_id < btree_id)
			btree_id_start++;

		ret = run_btree_triggers(trans, btree_id, btree_id_start);
@@ -558,11 +556,13 @@ static int bch2_trans_commit_run_triggers(struct btree_trans *trans)
			return ret;
	}

	trans_for_each_update(trans, i) {
	for (unsigned idx = 0; idx < trans->nr_updates; idx++) {
		struct btree_insert_entry *i = trans->updates + idx;

		if (i->btree_id > BTREE_ID_alloc)
			break;
		if (i->btree_id == BTREE_ID_alloc) {
			ret = run_btree_triggers(trans, BTREE_ID_alloc, i);
			ret = run_btree_triggers(trans, BTREE_ID_alloc, idx);
			if (ret)
				return ret;
			break;
@@ -826,7 +826,8 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, unsigned flags
	struct bch_fs *c = trans->c;
	int ret = 0, u64s_delta = 0;

	trans_for_each_update(trans, i) {
	for (unsigned idx = 0; idx < trans->nr_updates; idx++) {
		struct btree_insert_entry *i = trans->updates + idx;
		if (i->cached)
			continue;