From b7fc7f3777582dea85156a821d78a522a0c083aa Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:24 -0700 Subject: 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 Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index e6d08ee..2efd70c 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -325,24 +325,24 @@ static int iblock_execute_unmap(struct se_cmd *cmd) struct iblock_dev *ibd = dev->dev_ptr; unsigned char *buf, *ptr = NULL; sector_t lba; - unsigned int size = cmd->data_length, range; - int ret = 0, offset; - unsigned short dl, bd_dl; - - /* First UNMAP block descriptor starts at 8 byte offset */ - offset = 8; - size -= 8; + int size = cmd->data_length; + u32 range; + int ret = 0; + int dl, bd_dl; buf = transport_kmap_data_sg(cmd); dl = get_unaligned_be16(&buf[0]); bd_dl = get_unaligned_be16(&buf[2]); - ptr = &buf[offset]; - pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" + size = min(size - 8, bd_dl); + + /* 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); - while (size) { + while (size >= 16) { lba = get_unaligned_be64(&ptr[0]); range = get_unaligned_be32(&ptr[8]); pr_debug("UNMAP: Using lba: %llu and range: %u\n", -- cgit v0.10.2