Skip to content

Commit 7c2fd76

Browse files
puranjaymohankeithbusch
authored andcommitted
nvme: fix metadata handling in nvme-passthrough
On an NVMe namespace that does not support metadata, it is possible to send an IO command with metadata through io-passthru. This allows issues like [1] to trigger in the completion code path. nvme_map_user_request() doesn't check if the namespace supports metadata before sending it forward. It also allows admin commands with metadata to be processed as it ignores metadata when bdev == NULL and may report success. Reject an IO command with metadata when the NVMe namespace doesn't support it and reject an admin command if it has metadata. [1] https://lore.kernel.org/all/[email protected]/ Suggested-by: Christoph Hellwig <[email protected]> Signed-off-by: Puranjay Mohan <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Reviewed-by: Anuj Gupta <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent cead0b8 commit 7c2fd76

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

drivers/nvme/host/ioctl.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (c) 2017-2021 Christoph Hellwig.
55
*/
66
#include <linux/bio-integrity.h>
7+
#include <linux/blk-integrity.h>
78
#include <linux/ptrace.h> /* for force_successful_syscall_return */
89
#include <linux/nvme_ioctl.h>
910
#include <linux/io_uring/cmd.h>
@@ -119,9 +120,14 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
119120
struct request_queue *q = req->q;
120121
struct nvme_ns *ns = q->queuedata;
121122
struct block_device *bdev = ns ? ns->disk->part0 : NULL;
123+
bool supports_metadata = bdev && blk_get_integrity(bdev->bd_disk);
124+
bool has_metadata = meta_buffer && meta_len;
122125
struct bio *bio = NULL;
123126
int ret;
124127

128+
if (has_metadata && !supports_metadata)
129+
return -EINVAL;
130+
125131
if (ioucmd && (ioucmd->flags & IORING_URING_CMD_FIXED)) {
126132
struct iov_iter iter;
127133

@@ -143,15 +149,15 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
143149
goto out;
144150

145151
bio = req->bio;
146-
if (bdev) {
152+
if (bdev)
147153
bio_set_dev(bio, bdev);
148-
if (meta_buffer && meta_len) {
149-
ret = bio_integrity_map_user(bio, meta_buffer, meta_len,
150-
meta_seed);
151-
if (ret)
152-
goto out_unmap;
153-
req->cmd_flags |= REQ_INTEGRITY;
154-
}
154+
155+
if (has_metadata) {
156+
ret = bio_integrity_map_user(bio, meta_buffer, meta_len,
157+
meta_seed);
158+
if (ret)
159+
goto out_unmap;
160+
req->cmd_flags |= REQ_INTEGRITY;
155161
}
156162

157163
return ret;

0 commit comments

Comments
 (0)