nvmet-rdma: reject inline data with a nonzero offset#926
nvmet-rdma: reject inline data with a nonzero offset#926blktests-ci[bot] wants to merge 1 commit into
Conversation
|
Upstream branch: ba3e43a |
fc36596 to
7bed9c3
Compare
|
Upstream branch: ddd664b |
ed90165 to
13456aa
Compare
7bed9c3 to
a7bb5c5
Compare
|
Upstream branch: 979c294 |
13456aa to
f062b2a
Compare
a7bb5c5 to
5e41a3b
Compare
|
Upstream branch: acb7500 |
f062b2a to
2adb33f
Compare
5e41a3b to
c3a084b
Compare
|
Upstream branch: 9716c08 |
2adb33f to
0db0a31
Compare
c3a084b to
5f78e5d
Compare
|
Upstream branch: 2a2974b |
0db0a31 to
78499c3
Compare
5f78e5d to
e48f9db
Compare
|
Upstream branch: 062871f |
78499c3 to
4039e4b
Compare
199644a to
e6d9eb8
Compare
|
Upstream branch: 66affa3 |
4039e4b to
08fd7e8
Compare
e6d9eb8 to
7d8604f
Compare
|
Upstream branch: bade58e |
08fd7e8 to
61b9ec2
Compare
7d8604f to
4cc45a3
Compare
|
Upstream branch: 4edcdef |
61b9ec2 to
ff374e3
Compare
4cc45a3 to
90ffd56
Compare
nvmet_rdma_map_sgl_inline() takes a host-controlled offset and length
from the inline SGL descriptor and bounds-checks them against the
per-port inline_data_size:
u64 off = le64_to_cpu(sgl->addr);
u32 len = le32_to_cpu(sgl->length);
...
if (off + len > rsp->queue->dev->inline_data_size)
return NVME_SC_SGL_INVALID_OFFSET | NVME_STATUS_DNR;
This is unsound whenever the offset is nonzero:
- "off + len" is evaluated in u64 and wraps modulo 2^64. A descriptor
with addr = 0xfffffffffffffe00 and length = 0x1000 wraps the sum to
0xe00 and passes the check. nvmet_rdma_use_inline_sg() then stores
the offset into scatterlist::offset (unsigned int) and the block
layer reads out of bounds of the inline page; a large len also makes
num_pages(len) exceed NVMET_RDMA_MAX_INLINE_SGE and overruns the
fixed-size inline_sg[] array.
- Even computed without wrapping, inline_data_size is configurable up
to max(SZ_16K, PAGE_SIZE). An offset in (PAGE_SIZE, inline_data_size]
passes the bound and then "PAGE_SIZE - off" in
nvmet_rdma_use_inline_sg() underflows, leaving scatterlist::length at
~4 GiB and the offset pointing past the first inline page.
A nonzero inline offset is never legitimate here. nvmet advertises
icdoff = 0, nvme_rdma_setup_ctrl() refuses to use a controller that
reports a nonzero icdoff ("icdoff is not supported!"), and
nvme_rdma_map_sg_inline() sets the inline descriptor addr to icdoff, so
a compliant initiator always sends offset 0. nvmet_rdma_use_inline_sg()
likewise assumes the inline data begins at the start of the first inline
page (the RNIC DMAs it to page offset 0); any nonzero offset also
mis-describes the scatterlist even when it is in bounds.
Reject a nonzero offset directly. This closes the u64 overflow, the
inline_sg[] overrun and the PAGE_SIZE - off underflow together, and is
simpler than bounding the offset.
Fixes: 0d5ee2b ("nvmet-rdma: support max(16KB, PAGE_SIZE) inline data")
Cc: stable@vger.kernel.org
Reported-by: Bryam Vargas <hexlabsecurity@proton.me>
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
|
Upstream branch: dc59e4f |
ff374e3 to
f04360f
Compare
Pull request for series with
subject: nvmet-rdma: reject inline data with a nonzero offset
version: 1
url: https://patchwork.kernel.org/project/linux-block/list/?series=1105801