Skip to content

Commit 2fd5dcb

Browse files
hcleesmfrench
authored andcommitted
ksmbd: smbd: fix missing client's memory region invalidation
if the Channel of a SMB2 WRITE request is SMB2_CHANNEL_RDMA_V1_INVALIDTE, a client does not invalidate its memory regions but ksmbd must do it by sending a SMB2 WRITE response with IB_WR_SEND_WITH_INV. But if errors occur while processing a SMB2 READ/WRITE request, ksmbd sends a response with IB_WR_SEND. So a client could use memory regions already in use. Acked-by: Namjae Jeon <[email protected]> Signed-off-by: Hyunchul Lee <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 136dff3 commit 2fd5dcb

File tree

1 file changed

+46
-27
lines changed

1 file changed

+46
-27
lines changed

fs/ksmbd/smb2pdu.c

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6124,25 +6124,33 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
61246124
return err;
61256125
}
61266126

6127-
static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work,
6128-
struct smb2_read_req *req, void *data_buf,
6129-
size_t length)
6127+
static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work,
6128+
struct smb2_buffer_desc_v1 *desc,
6129+
__le32 Channel,
6130+
__le16 ChannelInfoOffset,
6131+
__le16 ChannelInfoLength)
61306132
{
6131-
struct smb2_buffer_desc_v1 *desc =
6132-
(struct smb2_buffer_desc_v1 *)&req->Buffer[0];
6133-
int err;
6134-
61356133
if (work->conn->dialect == SMB30_PROT_ID &&
6136-
req->Channel != SMB2_CHANNEL_RDMA_V1)
6134+
Channel != SMB2_CHANNEL_RDMA_V1)
61376135
return -EINVAL;
61386136

6139-
if (req->ReadChannelInfoOffset == 0 ||
6140-
le16_to_cpu(req->ReadChannelInfoLength) < sizeof(*desc))
6137+
if (ChannelInfoOffset == 0 ||
6138+
le16_to_cpu(ChannelInfoLength) < sizeof(*desc))
61416139
return -EINVAL;
61426140

61436141
work->need_invalidate_rkey =
6144-
(req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
6142+
(Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
61456143
work->remote_key = le32_to_cpu(desc->token);
6144+
return 0;
6145+
}
6146+
6147+
static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work,
6148+
struct smb2_read_req *req, void *data_buf,
6149+
size_t length)
6150+
{
6151+
struct smb2_buffer_desc_v1 *desc =
6152+
(struct smb2_buffer_desc_v1 *)&req->Buffer[0];
6153+
int err;
61466154

61476155
err = ksmbd_conn_rdma_write(work->conn, data_buf, length,
61486156
le32_to_cpu(desc->token),
@@ -6165,7 +6173,7 @@ int smb2_read(struct ksmbd_work *work)
61656173
struct ksmbd_conn *conn = work->conn;
61666174
struct smb2_read_req *req;
61676175
struct smb2_read_rsp *rsp;
6168-
struct ksmbd_file *fp;
6176+
struct ksmbd_file *fp = NULL;
61696177
loff_t offset;
61706178
size_t length, mincount;
61716179
ssize_t nbytes = 0, remain_bytes = 0;
@@ -6179,6 +6187,18 @@ int smb2_read(struct ksmbd_work *work)
61796187
return smb2_read_pipe(work);
61806188
}
61816189

6190+
if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||
6191+
req->Channel == SMB2_CHANNEL_RDMA_V1) {
6192+
err = smb2_set_remote_key_for_rdma(work,
6193+
(struct smb2_buffer_desc_v1 *)
6194+
&req->Buffer[0],
6195+
req->Channel,
6196+
req->ReadChannelInfoOffset,
6197+
req->ReadChannelInfoLength);
6198+
if (err)
6199+
goto out;
6200+
}
6201+
61826202
fp = ksmbd_lookup_fd_slow(work, le64_to_cpu(req->VolatileFileId),
61836203
le64_to_cpu(req->PersistentFileId));
61846204
if (!fp) {
@@ -6364,21 +6384,6 @@ static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work,
63646384

63656385
desc = (struct smb2_buffer_desc_v1 *)&req->Buffer[0];
63666386

6367-
if (work->conn->dialect == SMB30_PROT_ID &&
6368-
req->Channel != SMB2_CHANNEL_RDMA_V1)
6369-
return -EINVAL;
6370-
6371-
if (req->Length != 0 || req->DataOffset != 0)
6372-
return -EINVAL;
6373-
6374-
if (req->WriteChannelInfoOffset == 0 ||
6375-
le16_to_cpu(req->WriteChannelInfoLength) < sizeof(*desc))
6376-
return -EINVAL;
6377-
6378-
work->need_invalidate_rkey =
6379-
(req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
6380-
work->remote_key = le32_to_cpu(desc->token);
6381-
63826387
data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
63836388
if (!data_buf)
63846389
return -ENOMEM;
@@ -6425,6 +6430,20 @@ int smb2_write(struct ksmbd_work *work)
64256430
return smb2_write_pipe(work);
64266431
}
64276432

6433+
if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||
6434+
req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) {
6435+
if (req->Length != 0 || req->DataOffset != 0)
6436+
return -EINVAL;
6437+
err = smb2_set_remote_key_for_rdma(work,
6438+
(struct smb2_buffer_desc_v1 *)
6439+
&req->Buffer[0],
6440+
req->Channel,
6441+
req->WriteChannelInfoOffset,
6442+
req->WriteChannelInfoLength);
6443+
if (err)
6444+
goto out;
6445+
}
6446+
64286447
if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
64296448
ksmbd_debug(SMB, "User does not have write permission\n");
64306449
err = -EACCES;

0 commit comments

Comments
 (0)