mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-20 14:16:31 +00:00
scst_vdisk: Avoid triggering BUG() for large LBA's
The LBA field in READ(16) and READ(32) commands is 64 bits wide. Hence it is possible for an initiator not only to specify an offset that exceeds 2**63. Report an error to the initiator for such large offsets instead of triggering a BUG(). This patch fixes the following bug: BUG at scst/src/dev_handlers/scst_vdisk.c:1273 ((loff < 0) || __builtin_expect(!!(data_len < 0), 0)) ------------[ cut here ]------------ kernel BUG at /home/bart/software/scst.git/scst/src/dev_handlers/scst_vdisk.c:1273! invalid opcode: 0000 [#1] SMP CPU: 0 PID: 2852 Comm: iscsird3 Tainted: G O 3.10.0-rc1-debug+ #1 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 RIP: 0010:[<ffffffffa0309e76>] [<ffffffffa0309e76>] vdisk_parse_offset+0x3b6/0x490 [scst_vdisk] Call Trace: [<ffffffffa030dec9>] fileio_alloc_and_parse+0x69/0x130 [scst_vdisk] [<ffffffffa030e08b>] vdisk_parse+0x3b/0xc0 [scst_vdisk] [<ffffffffa0264a2e>] scst_parse_cmd+0x8e/0xd00 [scst] [<ffffffffa029b953>] ? spin_unlock_irqrestore.constprop.0+0x13/0x20 [scst] [<ffffffffa029bad5>] ? debug_print_with_prefix+0x165/0x1f0 [scst] [<ffffffffa026c2a5>] scst_process_active_cmd+0x425/0x760 [scst] [<ffffffffa026dc7a>] scst_cmd_init_done+0x2ea/0x5c0 [scst] [<ffffffffa032aaa2>] scst_cmd_init_stage1_done.constprop.37+0x12/0x20 [iscsi_scst] [<ffffffffa03317a4>] scsi_cmnd_start+0x1f4/0x550 [iscsi_scst] [<ffffffffa0332298>] cmnd_rx_start+0x148/0x1a0 [iscsi_scst] [<ffffffffa03353a8>] process_read_io+0x3c8/0x7f0 [iscsi_scst] [<ffffffff81049929>] ? local_bh_enable_ip+0x89/0xf0 [<ffffffffa0335894>] scst_do_job_rd+0xc4/0x220 [iscsi_scst] [<ffffffffa0335e65>] istrd+0x165/0x2e0 [iscsi_scst] [<ffffffff8106da50>] ? wake_up_bit+0x40/0x40 [<ffffffffa0335d00>] ? iscsi_task_mgmt_affected_cmds_done+0x240/0x240 [iscsi_scst] [<ffffffff8106d34b>] kthread+0xdb/0xe0 [<ffffffff8106d270>] ? kthread_create_on_node+0x120/0x120 [<ffffffff815357ac>] ret_from_fork+0x7c/0xb0 [<ffffffff8106d270>] ? kthread_create_on_node+0x120/0x120 ---[ end trace c21ad13002ef1548 ]--- --- scst/src/scst_lib.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4903 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+27
-3
@@ -6976,12 +6976,25 @@ int scst_calc_block_shift(int sector_size)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_calc_block_shift);
|
||||
|
||||
/*
|
||||
* Test whether the result of a shift-left operation would be larger than
|
||||
* what fits in a variable with the type of @a.
|
||||
*/
|
||||
#define shift_left_overflows(a, b) \
|
||||
({ \
|
||||
typeof (a) _minus_one = -1LL; \
|
||||
bool _a_is_signed = _minus_one < 0; \
|
||||
int _shift = sizeof(1ULL) * 8 - ((b) + _a_is_signed); \
|
||||
_shift < 0 || ((a) & ~((1ULL << _shift) - 1)) != 0; \
|
||||
})
|
||||
|
||||
/**
|
||||
* scst_generic_parse() - Generic parse() for devices supporting an LBA
|
||||
*/
|
||||
static inline int scst_generic_parse(struct scst_cmd *cmd, const int timeout[3])
|
||||
{
|
||||
int res = 0;
|
||||
const int block_shift = cmd->dev->block_shift;
|
||||
int res = -EINVAL;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -6991,7 +7004,6 @@ static inline int scst_generic_parse(struct scst_cmd *cmd, const int timeout[3])
|
||||
*/
|
||||
|
||||
if (cmd->op_flags & SCST_TRANSFER_LEN_TYPE_FIXED) {
|
||||
int block_shift = cmd->dev->block_shift;
|
||||
/*
|
||||
* No need for locks here, since *_detach() can not be
|
||||
* called, when there are existing commands.
|
||||
@@ -7001,8 +7013,20 @@ static inline int scst_generic_parse(struct scst_cmd *cmd, const int timeout[3])
|
||||
cmd->out_bufflen = cmd->out_bufflen << block_shift;
|
||||
}
|
||||
|
||||
cmd->timeout = timeout[cmd->op_flags & SCST_BOTH_TIMEOUTS];
|
||||
if (unlikely(!(cmd->op_flags & SCST_LBA_NOT_VALID) &&
|
||||
shift_left_overflows(cmd->lba, block_shift))) {
|
||||
PRINT_WARNING("offset %llu * %u >= 2**63 for device %s (len %lld)",
|
||||
cmd->lba, 1 << block_shift, cmd->dev->virt_name,
|
||||
cmd->data_len);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
|
||||
scst_sense_block_out_range_error));
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->timeout = timeout[cmd->op_flags & SCST_BOTH_TIMEOUTS];
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_DBG("res %d, bufflen %d, data_len %lld, direct %d", res,
|
||||
cmd->bufflen, (long long)cmd->data_len, cmd->data_direction);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user