target: Avoid mappedlun symlink creation during lun shutdown
authorNicholas Bellinger <nab@linux-iscsi.org>
Mon, 27 Mar 2017 23:12:43 +0000 (16:12 -0700)
committerWilly Tarreau <w@1wt.eu>
Wed, 1 Nov 2017 21:12:44 +0000 (22:12 +0100)
commit 49cb77e297dc611a1b795cfeb79452b3002bd331 upstream.

This patch closes a race between se_lun deletion during configfs
unlink in target_fabric_port_unlink() -> core_dev_del_lun()
-> core_tpg_remove_lun(), when transport_clear_lun_ref() blocks
waiting for percpu_ref RCU grace period to finish, but a new
NodeACL mappedlun is added before the RCU grace period has
completed.

This can happen in target_fabric_mappedlun_link() because it
only checks for se_lun->lun_se_dev, which is not cleared until
after transport_clear_lun_ref() percpu_ref RCU grace period
finishes.

This bug originally manifested as NULL pointer dereference
OOPsen in target_stat_scsi_att_intr_port_show_attr_dev() on
v4.1.y code, because it dereferences lun->lun_se_dev without
a explicit NULL pointer check.

In post v4.1 code with target-core RCU conversion, the code
in target_stat_scsi_att_intr_port_show_attr_dev() no longer
uses se_lun->lun_se_dev, but the same race still exists.

To address the bug, go ahead and set se_lun>lun_shutdown as
early as possible in core_tpg_remove_lun(), and ensure new
NodeACL mappedlun creation in target_fabric_mappedlun_link()
fails during se_lun shutdown.

Reported-by: James Shen <jcs@datera.io>
Cc: James Shen <jcs@datera.io>
Tested-by: James Shen <jcs@datera.io>
Cc: stable@vger.kernel.org # 3.10+
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Willy Tarreau <w@1wt.eu>
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_tpg.c
include/target/target_core_base.h

index 04c775cb3e65ec9a3905d19c34dfea33f28c5705..179f7810d39824f99fcce410079ca419721b3239 100644 (file)
@@ -84,6 +84,11 @@ static int target_fabric_mappedlun_link(
                                "_tpg does not exist\n");
                return -EINVAL;
        }
+       if (lun->lun_shutdown) {
+               pr_err("Unable to create mappedlun symlink because"
+                       " lun->lun_shutdown=true\n");
+               return -EINVAL;
+       }
        se_tpg = lun->lun_sep->sep_tpg;
 
        nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item;
index 8572207e3d4d77cf7a800855043dd26be7362844..bc3092f032b0dd13641a1b53c60eb76c567de8f5 100644 (file)
@@ -839,6 +839,8 @@ static void core_tpg_shutdown_lun(
        struct se_portal_group *tpg,
        struct se_lun *lun)
 {
+       lun->lun_shutdown = true;
+
        core_clear_lun_from_tpg(lun, tpg);
        transport_clear_lun_from_sessions(lun);
 }
@@ -868,6 +870,7 @@ struct se_lun *core_tpg_pre_dellun(
                spin_unlock(&tpg->tpg_lun_lock);
                return ERR_PTR(-ENODEV);
        }
+       lun->lun_shutdown = false;
        spin_unlock(&tpg->tpg_lun_lock);
 
        return lun;
index 7d99c0b5b7895c964c23cf6c776f3c918d463bbe..8e271438f77c2bfb629a61ba54fd3242fe0e8c84 100644 (file)
@@ -729,6 +729,7 @@ struct se_port_stat_grps {
 struct se_lun {
 #define SE_LUN_LINK_MAGIC                      0xffff7771
        u32                     lun_link_magic;
+       bool                    lun_shutdown;
        /* See transport_lun_status_table */
        enum transport_lun_status_table lun_status;
        u32                     lun_access;