| From adf9c800af3f75436ccf88870c4a08168150f32f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 23 Dec 2016 11:37:55 +0100 |
| Subject: target: bounds check XCOPY segment descriptor list |
| |
| From: David Disseldorp <ddiss@suse.de> |
| |
| [ Upstream commit af9f62c1686268c0517b289274d38f3a03bebd2a ] |
| |
| Check the length of the XCOPY request segment descriptor list against |
| the value advertised via the MAXIMUM SEGMENT DESCRIPTOR COUNT field in |
| the RECEIVE COPY OPERATING PARAMETERS response. |
| |
| spc4r37 6.4.3.5 states: |
| If the number of segment descriptors exceeds the allowed number, the |
| copy manager shall terminate the command with CHECK CONDITION status, |
| with the sense key set to ILLEGAL REQUEST, and the additional sense |
| code set to TOO MANY SEGMENT DESCRIPTORS. |
| |
| This functionality is testable using the libiscsi |
| ExtendedCopy.DescrLimits test. |
| |
| Signed-off-by: David Disseldorp <ddiss@suse.de> |
| Reviewed-by: Christoph Hellwig <hch@lst.de> |
| Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/target/target_core_xcopy.c | 14 ++++++++++++-- |
| 1 file changed, 12 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c |
| index 18848ba8d2ba0..a63b2fff82cc6 100644 |
| --- a/drivers/target/target_core_xcopy.c |
| +++ b/drivers/target/target_core_xcopy.c |
| @@ -305,17 +305,26 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op |
| |
| static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, |
| struct xcopy_op *xop, unsigned char *p, |
| - unsigned int sdll) |
| + unsigned int sdll, sense_reason_t *sense_ret) |
| { |
| unsigned char *desc = p; |
| unsigned int start = 0; |
| int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0; |
| |
| + *sense_ret = TCM_INVALID_PARAMETER_LIST; |
| + |
| if (offset != 0) { |
| pr_err("XCOPY segment descriptor list length is not" |
| " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN); |
| return -EINVAL; |
| } |
| + if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) { |
| + pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too" |
| + " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll); |
| + /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */ |
| + *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS; |
| + return -EINVAL; |
| + } |
| |
| while (start < sdll) { |
| /* |
| @@ -913,7 +922,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) |
| seg_desc = &p[16]; |
| seg_desc += (rc * XCOPY_TARGET_DESC_LEN); |
| |
| - rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll); |
| + rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, |
| + sdll, &ret); |
| if (rc <= 0) { |
| xcopy_pt_undepend_remotedev(xop); |
| goto out; |
| -- |
| 2.27.0 |
| |