vhost: copy virtio_blk_outhdr to local struct

Some SeaBIOS versions are not aligning virtio_blk_outhdr
on 8-byte boundary, causing ubsan failures.  To be safe,
let's just make sure on our end that we only access a
properly aligned structure by copying this small (16-byte)
data structure to a local structure variable.

Fixes issue #2452.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: Iacad72c3a1759fb8dc5ba411272a34d93ef2a6fc
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12238
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Jim Harris 2022-04-09 10:50:08 +00:00 committed by Tomasz Zawadzki
parent df80e8ffc6
commit 7778bc3a33

View File

@ -464,7 +464,7 @@ process_blk_request(struct spdk_vhost_blk_task *task,
struct spdk_vhost_blk_session *bvsession)
{
struct spdk_vhost_blk_dev *bvdev = bvsession->bvdev;
const struct virtio_blk_outhdr *req;
struct virtio_blk_outhdr req;
struct virtio_blk_discard_write_zeroes *desc;
struct iovec *iov;
uint32_t type;
@ -474,15 +474,19 @@ process_blk_request(struct spdk_vhost_blk_task *task,
int rc;
iov = &task->iovs[0];
if (spdk_unlikely(iov->iov_len != sizeof(*req))) {
if (spdk_unlikely(iov->iov_len != sizeof(req))) {
SPDK_DEBUGLOG(vhost_blk,
"First descriptor size is %zu but expected %zu (req_idx = %"PRIu16").\n",
iov->iov_len, sizeof(*req), task->req_idx);
iov->iov_len, sizeof(req), task->req_idx);
invalid_blk_request(task, VIRTIO_BLK_S_UNSUPP);
return -1;
}
req = iov->iov_base;
/* Some SeaBIOS versions don't align the virtio_blk_outhdr on an 8-byte boundary, which
* triggers ubsan errors. So copy this small 16-byte structure to the stack to workaround
* this problem.
*/
memcpy(&req, iov->iov_base, sizeof(req));
iov = &task->iovs[task->iovcnt - 1];
if (spdk_unlikely(iov->iov_len != 1)) {
@ -495,10 +499,10 @@ process_blk_request(struct spdk_vhost_blk_task *task,
payload_len = task->payload_size;
task->status = iov->iov_base;
payload_len -= sizeof(*req) + sizeof(*task->status);
payload_len -= sizeof(req) + sizeof(*task->status);
iovcnt = task->iovcnt - 2;
type = req->type;
type = req.type;
#ifdef VIRTIO_BLK_T_BARRIER
/* Don't care about barrier for now (as QEMU's virtio-blk do). */
type &= ~VIRTIO_BLK_T_BARRIER;
@ -517,12 +521,12 @@ process_blk_request(struct spdk_vhost_blk_task *task,
if (type == VIRTIO_BLK_T_IN) {
task->used_len = payload_len + sizeof(*task->status);
rc = spdk_bdev_readv(bvdev->bdev_desc, bvsession->io_channel,
&task->iovs[1], iovcnt, req->sector * 512,
&task->iovs[1], iovcnt, req.sector * 512,
payload_len, blk_request_complete_cb, task);
} else if (!bvdev->readonly) {
task->used_len = sizeof(*task->status);
rc = spdk_bdev_writev(bvdev->bdev_desc, bvsession->io_channel,
&task->iovs[1], iovcnt, req->sector * 512,
&task->iovs[1], iovcnt, req.sector * 512,
payload_len, blk_request_complete_cb, task);
} else {
SPDK_DEBUGLOG(vhost_blk, "Device is in read-only mode!\n");
@ -598,7 +602,7 @@ process_blk_request(struct spdk_vhost_blk_task *task,
break;
case VIRTIO_BLK_T_FLUSH:
flush_bytes = spdk_bdev_get_num_blocks(bvdev->bdev) * spdk_bdev_get_block_size(bvdev->bdev);
if (req->sector != 0) {
if (req.sector != 0) {
SPDK_NOTICELOG("sector must be zero for flush command\n");
invalid_blk_request(task, VIRTIO_BLK_S_IOERR);
return -1;