Ver Fonte

[SCSI] aacraid: prohibit access to array container space

Problem description:
--------------------

The issue reported by one of the customer was able to read LBA beyond
the array reported size with "sg_read" utility. If N is the last block
address reported, then should not be able to read past N,
i.e. N+1. But in their case, reported last LBA=143134719.  So should
not have been able to read with LBA=143134720, but it is read without
failure, which means reported size to the OS is not correct and is
less than the actual last block address.

Solution:
---------

Firmware layer exposes lesser container capacity than the actual
one. It exposes [Actual size - Spitfire space(10MB)] to the OS, IO's
to the 10MB should be prohibited from the Linux driver. Driver checks
LBA boundary, if its greater than the array reported size then sets
sensekey to HARDWARE_ERROR and sends the notification to the MID
layer.

Signed-off-by: Mahesh Rajashekhara <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Rajashekhara, Mahesh há 15 anos atrás
pai
commit
da3cc679b2
1 ficheiros alterados com 34 adições e 0 exclusões
  1. 34 0
      drivers/scsi/aacraid/aachba.c

+ 34 - 0
drivers/scsi/aacraid/aachba.c

@@ -1608,6 +1608,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 	int status;
 	int status;
 	struct aac_dev *dev;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
 	struct fib * cmd_fibcontext;
+	int cid;
 
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	/*
 	/*
@@ -1657,6 +1658,22 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		break;
 		break;
 	}
 	}
+
+	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
+		cid = scmd_id(scsicmd);
+		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+			SAM_STAT_CHECK_CONDITION;
+		set_sense(&dev->fsa_dev[cid].sense_data,
+			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
+		scsicmd->scsi_done(scsicmd);
+		return 1;
+	}
+
 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	if (aac_adapter_bounds(dev,scsicmd,lba))
 	if (aac_adapter_bounds(dev,scsicmd,lba))
@@ -1698,6 +1715,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
 	int status;
 	int status;
 	struct aac_dev *dev;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
 	struct fib * cmd_fibcontext;
+	int cid;
 
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	/*
 	/*
@@ -1737,6 +1755,22 @@ static int aac_write(struct scsi_cmnd * scsicmd)
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		fua = scsicmd->cmnd[1] & 0x8;
 		fua = scsicmd->cmnd[1] & 0x8;
 	}
 	}
+
+	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
+		cid = scmd_id(scsicmd);
+		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+			SAM_STAT_CHECK_CONDITION;
+		set_sense(&dev->fsa_dev[cid].sense_data,
+			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
+		scsicmd->scsi_done(scsicmd);
+		return 1;
+	}
+
 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	if (aac_adapter_bounds(dev,scsicmd,lba))
 	if (aac_adapter_bounds(dev,scsicmd,lba))