mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-23 21:51:27 +00:00
scst: Avoid that scst_write_same() crashes for large data len
A quote from SBC-3 about WRITE SAME (10): "If the number of logical blocks specified to be unmapped or written exceeds the value indicated in the MAXIMUM WRITE SAME LENGTH field in the Block Limits VPD page (see 6.6.3), then the device server shall terminate the command with CHECK CONDITION status with the sense key set to ILLEGAL REQUEST and the additional sense code set to INVALID FIELD IN CDB." This patch fixes the following crash since with the current implementation data_len >= 2**63 makes (unsigned)ws_sg_cnt >= 2**31 and this causes sg_init_table() to crash as follows: BUG: unable to handle kernel paging request at 00000027ffffffe8 IP: [<ffffffff8120d51e>] sg_init_table+0x5e/0x90 CPU: 1 PID: 10297 Comm: disk014_1 Tainted: G O 3.11.0-debug+ #1 RIP: 0010:[<ffffffff8120d51e>] [<ffffffff8120d51e>] sg_init_table+0x5e/0x90 Call Trace: [<ffffffffa02e4b46>] scst_write_same+0x236/0x340 [scst] [<ffffffffa034db30>] ? vdisk_exec_write_same_unmap.isra.35+0x170/0x170 [scst_vdisk] [<ffffffffa034dba4>] vdisk_exec_write_same+0x74/0x170 [scst_vdisk] [<ffffffffa034824e>] vdev_do_job+0x15e/0x390 [scst_vdisk] [<ffffffffa03484a5>] vdisk_exec+0x25/0x70 [scst_vdisk] [<ffffffffa02cafb5>] scst_do_real_exec+0xa5/0x3d0 [scst] [<ffffffffa02ce2da>] scst_exec_check_blocking+0xea/0x310 [scst] [<ffffffffa02ce695>] scst_exec_check_sn+0x195/0x2f0 [scst] [<ffffffffa02cff31>] scst_process_active_cmd+0x521/0x750 [scst] [<ffffffffa02d01e1>] scst_do_job_active+0x81/0x1a0 [scst] [<ffffffffa02d0537>] scst_cmd_thread+0x157/0x340 [scst] [<ffffffff81069ea6>] kthread+0xd6/0xe0 [<ffffffff814debfc>] ret_from_fork+0x7c/0xb0 Signed-off-by: Bart Van Assche <bvanassche@acm.org> git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5122 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -2501,6 +2501,9 @@ struct scst_device {
|
||||
/* List of blocked commands, protected by dev_lock. */
|
||||
struct list_head blocked_cmd_list;
|
||||
|
||||
/* MAXIMUM WRITE SAME LENGTH in bytes */
|
||||
uint64_t max_write_same_len;
|
||||
|
||||
/* A list entry used during TM */
|
||||
struct list_head tm_dev_list_entry;
|
||||
|
||||
|
||||
@@ -2558,8 +2558,9 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
|
||||
}
|
||||
}
|
||||
|
||||
/* MAXIMUM WRITE SAME LENGTH (512MB) */
|
||||
put_unaligned_be64((512*1024*1024) >> dev->block_shift, &buf[36]);
|
||||
/* MAXIMUM WRITE SAME LENGTH (measured in blocks) */
|
||||
put_unaligned_be64(dev->max_write_same_len >>
|
||||
dev->block_shift, &buf[36]);
|
||||
|
||||
resp_len = buf[3] + 4;
|
||||
} else if ((0xB1 == cmd->cdb[2]) && (dev->type == TYPE_DISK)) {
|
||||
|
||||
@@ -4870,7 +4870,7 @@ void scst_write_same(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
if (cmd->sg_cnt != 1) {
|
||||
PRINT_ERROR("WRITE SAME must contain only single block of data "
|
||||
PRINT_WARNING("WRITE SAME must contain only single block of data "
|
||||
"in a single SG (cmd %p)", cmd);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_parameter_value_invalid));
|
||||
goto out_done;
|
||||
@@ -4881,6 +4881,14 @@ void scst_write_same(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
if (unlikely((uint64_t)cmd->data_len > cmd->dev->max_write_same_len)) {
|
||||
PRINT_WARNING("Invalid WRITE SAME data len %lld (max allowed "
|
||||
"%lld)", (long long)cmd->data_len,
|
||||
(long long)cmd->dev->max_write_same_len);
|
||||
scst_set_invalid_field_in_cdb(cmd, cmd->len_off, 0);
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
wsp = kzalloc(sizeof(*wsp), GFP_KERNEL);
|
||||
if (wsp == NULL) {
|
||||
PRINT_ERROR("Unable to allocate ws_priv (size %zd, cmd %p)",
|
||||
|
||||
@@ -2080,6 +2080,7 @@ assign:
|
||||
|
||||
dev->threads_num = handler->threads_num;
|
||||
dev->threads_pool_type = handler->threads_pool_type;
|
||||
dev->max_write_same_len = 512 * 1024 * 1024; /* 512 MB */
|
||||
|
||||
if (handler->attach) {
|
||||
TRACE_DBG("Calling new dev handler's attach(%p)", dev);
|
||||
|
||||
Reference in New Issue
Block a user