aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_iblock.c
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2012-07-16 18:34:24 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-07-16 20:35:36 -0400
commitb7fc7f3777582dea85156a821d78a522a0c083aa (patch)
treefa190792d308e5fa42728d0d805e3338e1279ea0 /drivers/target/target_core_iblock.c
parent1a5fa4576ec8a462313c7516b31d7453481ddbe8 (diff)
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>
Diffstat (limited to 'drivers/target/target_core_iblock.c')
-rw-r--r--drivers/target/target_core_iblock.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index e6d08ee3166e..2efd70ca0b1d 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)
325 struct iblock_dev *ibd = dev->dev_ptr; 325 struct iblock_dev *ibd = dev->dev_ptr;
326 unsigned char *buf, *ptr = NULL; 326 unsigned char *buf, *ptr = NULL;
327 sector_t lba; 327 sector_t lba;
328 unsigned int size = cmd->data_length, range; 328 int size = cmd->data_length;
329 int ret = 0, offset; 329 u32 range;
330 unsigned short dl, bd_dl; 330 int ret = 0;
331 331 int dl, bd_dl;
332 /* First UNMAP block descriptor starts at 8 byte offset */
333 offset = 8;
334 size -= 8;
335 332
336 buf = transport_kmap_data_sg(cmd); 333 buf = transport_kmap_data_sg(cmd);
337 334
338 dl = get_unaligned_be16(&buf[0]); 335 dl = get_unaligned_be16(&buf[0]);
339 bd_dl = get_unaligned_be16(&buf[2]); 336 bd_dl = get_unaligned_be16(&buf[2]);
340 337
341 ptr = &buf[offset]; 338 size = min(size - 8, bd_dl);
342 pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" 339
340 /* First UNMAP block descriptor starts at 8 byte offset */
341 ptr = &buf[8];
342 pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
343 " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); 343 " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
344 344
345 while (size) { 345 while (size >= 16) {
346 lba = get_unaligned_be64(&ptr[0]); 346 lba = get_unaligned_be64(&ptr[0]);
347 range = get_unaligned_be32(&ptr[8]); 347 range = get_unaligned_be32(&ptr[8]);
348 pr_debug("UNMAP: Using lba: %llu and range: %u\n", 348 pr_debug("UNMAP: Using lba: %llu and range: %u\n",