[RHEL7,COMMIT] ms/target: bounds check XCOPY segment descriptor list

Submitted by Konstantin Khorenko on April 3, 2018, 1:11 p.m.

Details

Message ID 201804031311.w33DBXFO024042@finist_ce7.work
State New
Series "target: backport bug fixes for XCOPY"
Headers show

Commit Message

Konstantin Khorenko April 3, 2018, 1:11 p.m.
The commit is pushed to "branch-rh7-3.10.0-693.21.1.vz7.46.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.21.1.vz7.46.3
------>
commit f7368e1711c24386a5d2d2c28560a4ca356d0f85
Author: David Disseldorp <ddiss@suse.de>
Date:   Tue Apr 3 16:11:32 2018 +0300

    ms/target: bounds check XCOPY segment descriptor list
    
    ML: 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: Andrei Vagin <avagin@openvz.org>
---
 drivers/target/target_core_xcopy.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index 5a68f2a37e78..5f97a9af51f4 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -307,17 +307,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) {
 		/*
@@ -948,7 +957,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;