xemu/hw/scsi/emulation.c
Paolo Bonzini 3d4a8bf0ee scsi-generic: avoid invalid access to struct when emulating block limits
Emulation of the block limits VPD page called back into scsi-disk.c,
which however expected the request to be for a SCSIDiskState and
accessed a scsi-generic device outside the bounds of its struct
(namely to retrieve s->max_unmap_size and s->max_io_size).

To avoid this, move the emulation code to a separate function that
takes a new SCSIBlockLimits struct and marshals it into the VPD
response format.

Reported-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2018-11-06 21:35:06 +01:00

43 lines
1.2 KiB
C

#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/bswap.h"
#include "hw/scsi/emulation.h"
int scsi_emulate_block_limits(uint8_t *outbuf, const SCSIBlockLimits *bl)
{
/* required VPD size with unmap support */
memset(outbuf, 0, 0x3c);
outbuf[0] = bl->wsnz; /* wsnz */
if (bl->max_io_sectors) {
/* optimal transfer length granularity. This field and the optimal
* transfer length can't be greater than maximum transfer length.
*/
stw_be_p(outbuf + 2, MIN(bl->min_io_size, bl->max_io_sectors));
/* maximum transfer length */
stl_be_p(outbuf + 4, bl->max_io_sectors);
/* optimal transfer length */
stl_be_p(outbuf + 8, MIN(bl->opt_io_size, bl->max_io_sectors));
} else {
stw_be_p(outbuf + 2, bl->min_io_size);
stl_be_p(outbuf + 8, bl->opt_io_size);
}
/* max unmap LBA count */
stl_be_p(outbuf + 16, bl->max_unmap_sectors);
/* max unmap descriptors */
stl_be_p(outbuf + 20, bl->max_unmap_descr);
/* optimal unmap granularity; alignment is zero */
stl_be_p(outbuf + 24, bl->unmap_sectors);
/* max write same size, make it the same as maximum transfer length */
stl_be_p(outbuf + 36, bl->max_io_sectors);
return 0x3c;
}