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

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.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent f52c0e08
...@@ -700,38 +700,45 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) ...@@ -700,38 +700,45 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
return 0; return 0;
} }
/* NULL returned = something went wrong, inform userspace */ static int nbd_read_reply(struct nbd_device *nbd, int index,
static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) struct nbd_reply *reply)
{ {
struct nbd_config *config = nbd->config; struct kvec iov = {.iov_base = reply, .iov_len = sizeof(*reply)};
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 iov_iter to; struct iov_iter to;
int ret = 0; int result;
reply.magic = 0; reply->magic = 0;
iov_iter_kvec(&to, READ, &iov, 1, sizeof(reply)); iov_iter_kvec(&to, READ, &iov, 1, sizeof(*reply));
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result < 0) { if (result < 0) {
if (!nbd_disconnected(config)) if (!nbd_disconnected(nbd->config))
dev_err(disk_to_dev(nbd->disk), dev_err(disk_to_dev(nbd->disk),
"Receive control failed (result %d)\n", result); "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", dev_err(disk_to_dev(nbd->disk), "Wrong magic (0x%lx)\n",
(unsigned long)ntohl(reply.magic)); (unsigned long)ntohl(reply->magic));
return ERR_PTR(-EPROTO); return -EPROTO;
} }
memcpy(&handle, reply.handle, sizeof(handle)); return 0;
}
/* 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); tag = nbd_handle_to_tag(handle);
hwq = blk_mq_unique_tag_to_hwq(tag); hwq = blk_mq_unique_tag_to_hwq(tag);
if (hwq < nbd->tag_set.nr_hw_queues) 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) ...@@ -774,9 +781,9 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
} }
if (ntohl(reply.error)) { if (ntohl(reply->error)) {
dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n", dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n",
ntohl(reply.error)); ntohl(reply->error));
cmd->status = BLK_STS_IOERR; cmd->status = BLK_STS_IOERR;
goto out; goto out;
} }
...@@ -785,6 +792,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) ...@@ -785,6 +792,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
if (rq_data_dir(req) != WRITE) { if (rq_data_dir(req) != WRITE) {
struct req_iterator iter; struct req_iterator iter;
struct bio_vec bvec; struct bio_vec bvec;
struct iov_iter to;
rq_for_each_segment(bvec, req, iter) { rq_for_each_segment(bvec, req, iter) {
iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len); 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) ...@@ -798,7 +806,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
* and let the timeout stuff handle resubmitting * and let the timeout stuff handle resubmitting
* this request onto another connection. * this request onto another connection.
*/ */
if (nbd_disconnected(config)) { if (nbd_disconnected(nbd->config)) {
cmd->status = BLK_STS_IOERR; cmd->status = BLK_STS_IOERR;
goto out; goto out;
} }
...@@ -822,24 +830,30 @@ static void recv_work(struct work_struct *work) ...@@ -822,24 +830,30 @@ static void recv_work(struct work_struct *work)
work); work);
struct nbd_device *nbd = args->nbd; struct nbd_device *nbd = args->nbd;
struct nbd_config *config = nbd->config; struct nbd_config *config = nbd->config;
struct nbd_sock *nsock;
struct nbd_cmd *cmd; struct nbd_cmd *cmd;
struct request *rq; struct request *rq;
while (1) { while (1) {
cmd = nbd_read_stat(nbd, args->index); struct nbd_reply reply;
if (IS_ERR(cmd)) {
struct nbd_sock *nsock = config->socks[args->index];
mutex_lock(&nsock->tx_lock); if (nbd_read_reply(nbd, args->index, &reply))
nbd_mark_nsock_dead(nbd, nsock, 1); break;
mutex_unlock(&nsock->tx_lock);
cmd = nbd_handle_reply(nbd, args->index, &reply);
if (IS_ERR(cmd))
break; break;
}
rq = blk_mq_rq_from_pdu(cmd); rq = blk_mq_rq_from_pdu(cmd);
if (likely(!blk_should_fake_timeout(rq->q))) if (likely(!blk_should_fake_timeout(rq->q)))
blk_mq_complete_request(rq); 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); nbd_config_put(nbd);
atomic_dec(&config->recv_threads); atomic_dec(&config->recv_threads);
wake_up(&config->recv_wq); wake_up(&config->recv_wq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment