From: Daniel Gomez <[email protected]> Once dma_blk_cb() chunks at IOV_MAX, a later patch drops the current mdts 2 MiB cap, allowing mdts (and zasl, which may be as large as mdts) to essentially be 32 or more. Ensure shifting doesn't go out of range by adding a static inline helper that clamps to UINT64_MAX when mdts or zasl shift operations exceed uint64_t width.
Fixes error with ubsan enabled and large mdts: ../hw/nvme/ctrl.c:1685:36: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int' Signed-off-by: Daniel Gomez <[email protected]> --- hw/nvme/ctrl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 4893cf7e741..a24a674a4c5 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -1713,11 +1713,18 @@ static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type) } } +static inline uint64_t nvme_max_data_transfer_size(NvmeCtrl *n, uint8_t exp) +{ + unsigned shift = n->page_bits + exp; + + return shift >= 64 ? UINT64_MAX : 1ULL << shift; +} + static inline uint16_t nvme_check_mdts(NvmeCtrl *n, size_t len) { uint8_t mdts = n->params.mdts; - if (mdts && len > n->page_size << mdts) { + if (mdts && len > nvme_max_data_transfer_size(n, mdts)) { trace_pci_nvme_err_mdts(len); return NVME_INVALID_FIELD | NVME_DNR; } @@ -3809,7 +3816,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, } if (n->params.zasl && - data_size > (uint64_t)n->page_size << n->params.zasl) { + data_size > nvme_max_data_transfer_size(n, n->params.zasl)) { trace_pci_nvme_err_zasl(data_size); return NVME_INVALID_FIELD | NVME_DNR; } -- 2.55.0
