From 575d2ac72342beea5c3d63fc655d5d173b01283a Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Tue, 2 Feb 2021 11:12:30 +0100 Subject: [RHEL7.9 KPATCH v2] [target] scsi: Fix XCOPY NAA identifier lookup Kernels: 3.10.0-1160.el7 3.10.0-1160.2.1.el7 3.10.0-1160.2.2.el7 3.10.0-1160.6.1.el7 3.10.0-1160.11.1.el7 Changes since last build: [x86_64]: target_core_xcopy.o: changed function: target_do_xcopy target_core_xcopy.o: changed function: target_parse_xcopy_cmd target_core_xcopy.o: changed function: target_xcopy_do_work target_core_xcopy.o: changed function: target_xcopy_locate_se_dev_e4 target_core_xcopy.o: changed function: xcopy_pt_undepend_remotedev [ppc64le]: target_core_xcopy.o: changed function: target_do_receive_copy_results target_core_xcopy.o: changed function: target_do_xcopy target_core_xcopy.o: changed function: target_parse_xcopy_cmd target_core_xcopy.o: changed function: target_xcopy_do_work target_core_xcopy.o: new function: target_xcopy_locate_se_dev_e4 target_core_xcopy.o: new function: xcopy_pt_undepend_remotedev --------------------------- Modifications: shadow var instead of structure fixup commit 173ce8ce7c0c334c3406b4826dca6732f101dd2e Author: Maurizio Lombardi Date: Mon Jan 18 16:24:30 2021 -0500 [target] scsi: Fix XCOPY NAA identifier lookup Message-id: <20210118162431.74459-1-mlombard@redhat.com> Patchwork-id: 10208 Patchwork-instance: patchwork-private O-Subject: [kernel team] [CVE-2020-28374 RHEL7.9.z e-stor PATCH] scsi: target: Fix XCOPY NAA identifier lookup Bugzilla: 1900469 CVE: CVE-2020-28374 RH-Acked-by: Tomas Henzl RH-Acked-by: Ewan D. Milne From: David Disseldorp BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1900469 Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34294843 Upstream: cherry-picked from the mainline tree When attempting to match EXTENDED COPY CSCD descriptors with corresponding se_devices, target_xcopy_locate_se_dev_e4() currently iterates over LIO's global devices list which includes all configured backstores. This change ensures that only initiator-accessible backstores are considered during CSCD descriptor lookup, according to the session's se_node_acl LUN list. To avoid LUN removal race conditions, device pinning is changed from being configfs based to instead using the se_node_acl lun_ref. Reference: CVE-2020-28374 Fixes: cbf031f425fd ("target: Add support for EXTENDED_COPY copy offload emulation") Reviewed-by: Lee Duncan Signed-off-by: David Disseldorp Signed-off-by: Mike Christie Signed-off-by: Martin K. Petersen (cherry picked from commit 2896c93811e39d63a4d9b63ccf12a8fbc226e5e4) Signed-off-by: Maurizio Lombardi Signed-off-by: Augusto Caringi Signed-off-by: Artem Savkov Acked-by: Joe Lawrence Acked-by: Josh Poimboeuf --- drivers/target/target_core_xcopy.c | 143 +++++++++++++++++++---------- 1 file changed, 95 insertions(+), 48 deletions(-) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 252de556dbb3..4d023e403845 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -38,6 +38,8 @@ #include "target_core_ua.h" #include "target_core_xcopy.h" +#define KLP_SHADOW_REMOTE_LUN_REF 0x2020283740000000 + static struct workqueue_struct *xcopy_wq = NULL; static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop); @@ -55,60 +57,83 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) return 0; } -struct xcopy_dev_search_info { - const unsigned char *dev_wwn; - struct se_device *found_dev; -}; - +/** + * target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers + * + * @se_dev: device being considered for match + * @dev_wwn: XCOPY requested NAA dev_wwn + * @return: 1 on match, 0 on no-match + */ static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev, - void *data) + const unsigned char *dev_wwn) { - struct xcopy_dev_search_info *info = data; unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; int rc; - if (!se_dev->dev_attrib.emulate_3pc) + if (!se_dev->dev_attrib.emulate_3pc) { + pr_debug("XCOPY: emulate_3pc disabled on se_dev %p\n", se_dev); return 0; + } memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); - rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); - if (rc != 0) - return 0; - - info->found_dev = se_dev; - pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); - - rc = target_depend_item(&se_dev->dev_group.cg_item); + rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); if (rc != 0) { - pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n", - rc, se_dev); - return rc; + pr_debug("XCOPY: skip non-matching: %*ph\n", + XCOPY_NAA_IEEE_REGEX_LEN, tmp_dev_wwn); + return 0; } + pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); - pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n", - se_dev, &se_dev->dev_group); return 1; } -static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, - struct se_device **found_dev) +static int target_xcopy_locate_se_dev_e4(struct se_session *sess, + const unsigned char *dev_wwn, + struct se_device **_found_dev, + struct percpu_ref **_found_lun_ref) { - struct xcopy_dev_search_info info; - int ret; - - memset(&info, 0, sizeof(info)); - info.dev_wwn = dev_wwn; - - ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info); - if (ret == 1) { - *found_dev = info.found_dev; - return 0; - } else { - pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); - return -EINVAL; + struct se_dev_entry *deve; + struct se_node_acl *nacl; + struct se_lun *this_lun = NULL; + struct se_device *found_dev = NULL; + + /* cmd with NULL sess indicates no associated $FABRIC_MOD */ + if (!sess) + goto err_out; + + pr_debug("XCOPY 0xe4: searching for: %*ph\n", + XCOPY_NAA_IEEE_REGEX_LEN, dev_wwn); + + nacl = sess->se_node_acl; + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + struct se_device *this_dev; + int rc; + + this_lun = rcu_dereference(deve->se_lun); + this_dev = rcu_dereference_raw(this_lun->lun_se_dev); + + rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn); + if (rc) { + if (percpu_ref_tryget_live(&this_lun->lun_ref)) + found_dev = this_dev; + break; + } } + rcu_read_unlock(); + if (found_dev == NULL) + goto err_out; + + pr_debug("lun_ref held for se_dev: %p se_dev->se_dev_group: %p\n", + found_dev, &found_dev->dev_group); + *_found_dev = found_dev; + *_found_lun_ref = &this_lun->lun_ref; + return 0; +err_out: + pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); + return -EINVAL; } static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, @@ -197,6 +222,8 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op return 0; } +#include "kpatch-macros.h" + static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, struct xcopy_op *xop, unsigned char *p, unsigned short tdll, sense_reason_t *sense_ret) @@ -206,6 +233,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, int offset = tdll % XCOPY_TARGET_DESC_LEN, rc; unsigned short cscd_index = 0; unsigned short start = 0; + struct percpu_ref **remote_lun_ref; *sense_ret = TCM_INVALID_PARAMETER_LIST; @@ -253,14 +281,24 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, } } + remote_lun_ref = klp_shadow_get_or_alloc(xop, KLP_SHADOW_REMOTE_LUN_REF, + sizeof(struct percpu_ref*), GFP_KERNEL, NULL, NULL); + + if (!remote_lun_ref) + goto out; + switch (xop->op_origin) { case XCOL_SOURCE_RECV_OP: - rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn, - &xop->dst_dev); + rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess, + xop->dst_tid_wwn, + &xop->dst_dev, + remote_lun_ref); break; case XCOL_DEST_RECV_OP: - rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn, - &xop->src_dev); + rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess, + xop->src_tid_wwn, + &xop->src_dev, + remote_lun_ref); break; default: pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - " @@ -406,18 +444,16 @@ static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd) static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop) { - struct se_device *remote_dev; + struct percpu_ref **remote_lun_ref = klp_shadow_get(xop, + KLP_SHADOW_REMOTE_LUN_REF); if (xop->op_origin == XCOL_SOURCE_RECV_OP) - remote_dev = xop->dst_dev; + pr_debug("putting dst lun_ref for %p\n", xop->dst_dev); else - remote_dev = xop->src_dev; + pr_debug("putting src lun_ref for %p\n", xop->src_dev); - pr_debug("Calling configfs_undepend_item for" - " remote_dev: %p remote_dev->dev_group: %p\n", - remote_dev, &remote_dev->dev_group.cg_item); - - target_undepend_item(&remote_dev->dev_group.cg_item); + if (remote_lun_ref) + percpu_ref_put(*remote_lun_ref); } static void xcopy_pt_release_cmd(struct se_cmd *se_cmd) @@ -857,6 +893,7 @@ static void target_xcopy_do_work(struct work_struct *work) } xcopy_pt_undepend_remotedev(xop); + klp_shadow_free(xop, KLP_SHADOW_REMOTE_LUN_REF, NULL); kfree(xop); pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n", @@ -872,6 +909,7 @@ out: xcopy_pt_undepend_remotedev(xop); err_free: + klp_shadow_free(xop, KLP_SHADOW_REMOTE_LUN_REF, NULL); kfree(xop); /* * Don't override an error scsi status if it has already been set @@ -981,6 +1019,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) struct se_device *dev = se_cmd->se_dev; struct xcopy_op *xop; unsigned int sa; + struct percpu_ref **remote_lun_ref; if (!dev->dev_attrib.emulate_3pc) { pr_err("EXTENDED_COPY operation explicitly disabled\n"); @@ -1006,6 +1045,12 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); if (!xop) goto err; + + remote_lun_ref = klp_shadow_alloc(xop, KLP_SHADOW_REMOTE_LUN_REF, + sizeof(struct percpu_ref*), GFP_KERNEL, NULL, NULL); + if (!remote_lun_ref) + goto xop_free; + xop->xop_se_cmd = se_cmd; INIT_WORK(&xop->xop_work, target_xcopy_do_work); if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work))) @@ -1013,6 +1058,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) return TCM_NO_SENSE; free: + klp_shadow_free(xop, KLP_SHADOW_REMOTE_LUN_REF, NULL); +xop_free: kfree(xop); err: -- 2.26.2