forked from Minki/linux
target: Fix possible integer underflow in UNMAP emulation
It's possible for an initiator to send us an UNMAP command with a descriptor that is less than 8 bytes; in that case it's really bad for us to set an unsigned int to that value, subtract 8 from it, and then use that as a limit for our loop (since the value will wrap around to a huge positive value). Fix this by making size be signed and only looping if size >= 16 (ie if we have at least a full descriptor available). Also remove offset as an obfuscated name for the constant 8. Signed-off-by: Roland Dreier <roland@purestorage.com> Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
parent
1a5fa4576e
commit
b7fc7f3777
@ -325,24 +325,24 @@ static int iblock_execute_unmap(struct se_cmd *cmd)
|
|||||||
struct iblock_dev *ibd = dev->dev_ptr;
|
struct iblock_dev *ibd = dev->dev_ptr;
|
||||||
unsigned char *buf, *ptr = NULL;
|
unsigned char *buf, *ptr = NULL;
|
||||||
sector_t lba;
|
sector_t lba;
|
||||||
unsigned int size = cmd->data_length, range;
|
int size = cmd->data_length;
|
||||||
int ret = 0, offset;
|
u32 range;
|
||||||
unsigned short dl, bd_dl;
|
int ret = 0;
|
||||||
|
int dl, bd_dl;
|
||||||
/* First UNMAP block descriptor starts at 8 byte offset */
|
|
||||||
offset = 8;
|
|
||||||
size -= 8;
|
|
||||||
|
|
||||||
buf = transport_kmap_data_sg(cmd);
|
buf = transport_kmap_data_sg(cmd);
|
||||||
|
|
||||||
dl = get_unaligned_be16(&buf[0]);
|
dl = get_unaligned_be16(&buf[0]);
|
||||||
bd_dl = get_unaligned_be16(&buf[2]);
|
bd_dl = get_unaligned_be16(&buf[2]);
|
||||||
|
|
||||||
ptr = &buf[offset];
|
size = min(size - 8, bd_dl);
|
||||||
pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
|
|
||||||
|
/* First UNMAP block descriptor starts at 8 byte offset */
|
||||||
|
ptr = &buf[8];
|
||||||
|
pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
|
||||||
" ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
|
" ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
|
||||||
|
|
||||||
while (size) {
|
while (size >= 16) {
|
||||||
lba = get_unaligned_be64(&ptr[0]);
|
lba = get_unaligned_be64(&ptr[0]);
|
||||||
range = get_unaligned_be32(&ptr[8]);
|
range = get_unaligned_be32(&ptr[8]);
|
||||||
pr_debug("UNMAP: Using lba: %llu and range: %u\n",
|
pr_debug("UNMAP: Using lba: %llu and range: %u\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user