Commit 3fe1db62 authored by Yu Kuai's avatar Yu Kuai Committed by Jens Axboe
Browse files

nbd: partition nbd_read_stat() into nbd_read_reply() and nbd_handle_reply()



Prepare to fix uaf in nbd_read_stat(), no functional changes.

Signed-off-by: default avatarYu Kuai <yukuai3@huawei.com>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Link: https://lore.kernel.org/r/20210916093350.1410403-7-yukuai3@huawei.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent f52c0e08
Loading
Loading
Loading
Loading
+44 −30
Original line number Diff line number Diff line
@@ -700,38 +700,45 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
	return 0;
}

/* NULL returned = something went wrong, inform userspace */
static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
static int nbd_read_reply(struct nbd_device *nbd, int index,
			  struct nbd_reply *reply)
{
	struct nbd_config *config = nbd->config;
	int result;
	struct nbd_reply reply;
	struct nbd_cmd *cmd;
	struct request *req = NULL;
	u64 handle;
	u16 hwq;
	u32 tag;
	struct kvec iov = {.iov_base = &reply, .iov_len = sizeof(reply)};
	struct kvec iov = {.iov_base = reply, .iov_len = sizeof(*reply)};
	struct iov_iter to;
	int ret = 0;
	int result;

	reply.magic = 0;
	iov_iter_kvec(&to, READ, &iov, 1, sizeof(reply));
	reply->magic = 0;
	iov_iter_kvec(&to, READ, &iov, 1, sizeof(*reply));
	result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
	if (result < 0) {
		if (!nbd_disconnected(config))
		if (!nbd_disconnected(nbd->config))
			dev_err(disk_to_dev(nbd->disk),
				"Receive control failed (result %d)\n", result);
		return ERR_PTR(result);
		return result;
	}

	if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
	if (ntohl(reply->magic) != NBD_REPLY_MAGIC) {
		dev_err(disk_to_dev(nbd->disk), "Wrong magic (0x%lx)\n",
				(unsigned long)ntohl(reply.magic));
		return ERR_PTR(-EPROTO);
				(unsigned long)ntohl(reply->magic));
		return -EPROTO;
	}

	return 0;
}

	memcpy(&handle, reply.handle, sizeof(handle));
/* NULL returned = something went wrong, inform userspace */
static struct nbd_cmd *nbd_handle_reply(struct nbd_device *nbd, int index,
					struct nbd_reply *reply)
{
	int result;
	struct nbd_cmd *cmd;
	struct request *req = NULL;
	u64 handle;
	u16 hwq;
	u32 tag;
	int ret = 0;

	memcpy(&handle, reply->handle, sizeof(handle));
	tag = nbd_handle_to_tag(handle);
	hwq = blk_mq_unique_tag_to_hwq(tag);
	if (hwq < nbd->tag_set.nr_hw_queues)
@@ -774,9 +781,9 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
		ret = -ENOENT;
		goto out;
	}
	if (ntohl(reply.error)) {
	if (ntohl(reply->error)) {
		dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n",
			ntohl(reply.error));
			ntohl(reply->error));
		cmd->status = BLK_STS_IOERR;
		goto out;
	}
@@ -785,6 +792,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
	if (rq_data_dir(req) != WRITE) {
		struct req_iterator iter;
		struct bio_vec bvec;
		struct iov_iter to;

		rq_for_each_segment(bvec, req, iter) {
			iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len);
@@ -798,7 +806,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
				 * and let the timeout stuff handle resubmitting
				 * this request onto another connection.
				 */
				if (nbd_disconnected(config)) {
				if (nbd_disconnected(nbd->config)) {
					cmd->status = BLK_STS_IOERR;
					goto out;
				}
@@ -822,24 +830,30 @@ static void recv_work(struct work_struct *work)
						     work);
	struct nbd_device *nbd = args->nbd;
	struct nbd_config *config = nbd->config;
	struct nbd_sock *nsock;
	struct nbd_cmd *cmd;
	struct request *rq;

	while (1) {
		cmd = nbd_read_stat(nbd, args->index);
		if (IS_ERR(cmd)) {
			struct nbd_sock *nsock = config->socks[args->index];
		struct nbd_reply reply;

			mutex_lock(&nsock->tx_lock);
			nbd_mark_nsock_dead(nbd, nsock, 1);
			mutex_unlock(&nsock->tx_lock);
		if (nbd_read_reply(nbd, args->index, &reply))
			break;

		cmd = nbd_handle_reply(nbd, args->index, &reply);
		if (IS_ERR(cmd))
			break;
		}

		rq = blk_mq_rq_from_pdu(cmd);
		if (likely(!blk_should_fake_timeout(rq->q)))
			blk_mq_complete_request(rq);
	}

	nsock = config->socks[args->index];
	mutex_lock(&nsock->tx_lock);
	nbd_mark_nsock_dead(nbd, nsock, 1);
	mutex_unlock(&nsock->tx_lock);

	nbd_config_put(nbd);
	atomic_dec(&config->recv_threads);
	wake_up(&config->recv_wq);