Commit ac84e82f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'block-5.17-2022-03-04' of git://git.kernel.dk/linux-block

Pull block fix from Jens Axboe:
 "Just a small UAF fix for blktrace"

* tag 'block-5.17-2022-03-04' of git://git.kernel.dk/linux-block:
  blktrace: fix use after free for struct blk_trace
parents 07ebd38a 30939293
Loading
Loading
Loading
Loading
+18 −8
Original line number Diff line number Diff line
@@ -310,10 +310,20 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
	local_irq_restore(flags);
}

static void blk_trace_free(struct blk_trace *bt)
static void blk_trace_free(struct request_queue *q, struct blk_trace *bt)
{
	relay_close(bt->rchan);

	/*
	 * If 'bt->dir' is not set, then both 'dropped' and 'msg' are created
	 * under 'q->debugfs_dir', thus lookup and remove them.
	 */
	if (!bt->dir) {
		debugfs_remove(debugfs_lookup("dropped", q->debugfs_dir));
		debugfs_remove(debugfs_lookup("msg", q->debugfs_dir));
	} else {
		debugfs_remove(bt->dir);
	}
	free_percpu(bt->sequence);
	free_percpu(bt->msg_data);
	kfree(bt);
@@ -335,10 +345,10 @@ static void put_probe_ref(void)
	mutex_unlock(&blk_probe_mutex);
}

static void blk_trace_cleanup(struct blk_trace *bt)
static void blk_trace_cleanup(struct request_queue *q, struct blk_trace *bt)
{
	synchronize_rcu();
	blk_trace_free(bt);
	blk_trace_free(q, bt);
	put_probe_ref();
}

@@ -352,7 +362,7 @@ static int __blk_trace_remove(struct request_queue *q)
		return -EINVAL;

	if (bt->trace_state != Blktrace_running)
		blk_trace_cleanup(bt);
		blk_trace_cleanup(q, bt);

	return 0;
}
@@ -572,7 +582,7 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
	ret = 0;
err:
	if (ret)
		blk_trace_free(bt);
		blk_trace_free(q, bt);
	return ret;
}

@@ -1616,7 +1626,7 @@ static int blk_trace_remove_queue(struct request_queue *q)

	put_probe_ref();
	synchronize_rcu();
	blk_trace_free(bt);
	blk_trace_free(q, bt);
	return 0;
}

@@ -1647,7 +1657,7 @@ static int blk_trace_setup_queue(struct request_queue *q,
	return 0;

free_bt:
	blk_trace_free(bt);
	blk_trace_free(q, bt);
	return ret;
}