Commit 3b84bbef authored by Jens Axboe's avatar Jens Axboe Committed by Greg Kroah-Hartman

libata: have ata_scsi_rw_xlat() fail invalid passthrough requests

[ Upstream commit 2d727150 ]

For passthrough requests, libata-scsi takes what the user passes in
as gospel. This can be problematic if the user fills in the CDB
incorrectly. One example of that is in request sizes. For read/write
commands, the CDB contains fields describing the transfer length of
the request. These should match with the SG_IO header fields, but
libata-scsi currently does no validation of that.

Check that the number of blocks in the CDB for passthrough requests
matches what was mapped into the request. If the CDB asks for more
data then the validated SG_IO header fields, error it.
Reported-by: default avatarKrishna Ram Prakash R <krp@gtux.in>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent e0c03022
...@@ -1803,6 +1803,21 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc) ...@@ -1803,6 +1803,21 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc)
return 1; return 1;
} }
static bool ata_check_nblocks(struct scsi_cmnd *scmd, u32 n_blocks)
{
struct request *rq = scmd->request;
u32 req_blocks;
if (!blk_rq_is_passthrough(rq))
return true;
req_blocks = blk_rq_bytes(rq) / scmd->device->sector_size;
if (n_blocks > req_blocks)
return false;
return true;
}
/** /**
* ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
* @qc: Storage for translated ATA taskfile * @qc: Storage for translated ATA taskfile
...@@ -1847,6 +1862,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) ...@@ -1847,6 +1862,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
scsi_10_lba_len(cdb, &block, &n_block); scsi_10_lba_len(cdb, &block, &n_block);
if (cdb[1] & (1 << 3)) if (cdb[1] & (1 << 3))
tf_flags |= ATA_TFLAG_FUA; tf_flags |= ATA_TFLAG_FUA;
if (!ata_check_nblocks(scmd, n_block))
goto invalid_fld;
break; break;
case READ_6: case READ_6:
case WRITE_6: case WRITE_6:
...@@ -1861,6 +1878,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) ...@@ -1861,6 +1878,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
*/ */
if (!n_block) if (!n_block)
n_block = 256; n_block = 256;
if (!ata_check_nblocks(scmd, n_block))
goto invalid_fld;
break; break;
case READ_16: case READ_16:
case WRITE_16: case WRITE_16:
...@@ -1871,6 +1890,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) ...@@ -1871,6 +1890,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
scsi_16_lba_len(cdb, &block, &n_block); scsi_16_lba_len(cdb, &block, &n_block);
if (cdb[1] & (1 << 3)) if (cdb[1] & (1 << 3))
tf_flags |= ATA_TFLAG_FUA; tf_flags |= ATA_TFLAG_FUA;
if (!ata_check_nblocks(scmd, n_block))
goto invalid_fld;
break; break;
default: default:
DPRINTK("no-byte command\n"); DPRINTK("no-byte command\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment