| From b1461b7f2636e5fda4450528f69a33d655c5d023 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 22 Aug 2020 00:48:10 +0800 |
| Subject: nvmet-tcp: Fix NULL dereference when a connect data comes in h2cdata |
| pdu |
| |
| From: Ziye Yang <ziye.yang@intel.com> |
| |
| [ Upstream commit a6ce7d7b4adaebc27ee7e78e5ecc378a1cfc221d ] |
| |
| When handling commands without in-capsule data, we assign the ttag |
| assuming we already have the queue commands array allocated (based |
| on the queue size information in the connect data payload). However |
| if the connect itself did not send the connect data in-capsule we |
| have yet to allocate the queue commands,and we will assign a bogus |
| ttag and suffer a NULL dereference when we receive the corresponding |
| h2cdata pdu. |
| |
| Fix this by checking if we already allocated commands before |
| dereferencing it when handling h2cdata, if we didn't, its for sure a |
| connect and we should use the preallocated connect command. |
| |
| Signed-off-by: Ziye Yang <ziye.yang@intel.com> |
| Signed-off-by: Sagi Grimberg <sagi@grimberg.me> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/nvme/target/tcp.c | 10 +++++++++- |
| 1 file changed, 9 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c |
| index 22014e76d7714..e31823f19a0fa 100644 |
| --- a/drivers/nvme/target/tcp.c |
| +++ b/drivers/nvme/target/tcp.c |
| @@ -150,6 +150,11 @@ static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd); |
| static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue, |
| struct nvmet_tcp_cmd *cmd) |
| { |
| + if (unlikely(!queue->nr_cmds)) { |
| + /* We didn't allocate cmds yet, send 0xffff */ |
| + return USHRT_MAX; |
| + } |
| + |
| return cmd - queue->cmds; |
| } |
| |
| @@ -847,7 +852,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) |
| struct nvme_tcp_data_pdu *data = &queue->pdu.data; |
| struct nvmet_tcp_cmd *cmd; |
| |
| - cmd = &queue->cmds[data->ttag]; |
| + if (likely(queue->nr_cmds)) |
| + cmd = &queue->cmds[data->ttag]; |
| + else |
| + cmd = &queue->connect; |
| |
| if (le32_to_cpu(data->data_offset) != cmd->rbytes_done) { |
| pr_err("ttag %u unexpected data offset %u (expected %u)\n", |
| -- |
| 2.25.1 |
| |