diff options
| author | Roland Dreier <roland@purestorage.com> | 2012-06-05 02:37:34 -0400 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-06-12 23:12:25 -0400 |
| commit | 3578ddba1ae93263d373e7bc85fd38d1f0368b78 (patch) | |
| tree | c62e16158acdd7eea4106d56883352d114ac499f | |
| parent | 59e4f541baf728dbb426949bfa9f6862387ffd0e (diff) | |
tcm_qla2xxx: Don't insert nacls without sessions into the btree
When we create an explicit node ACL in tcm_qla2xxx_make_nodeacl(),
there is a call to tcm_qla2xxx_setup_nacl_from_rport(), which puts the
node ACL into the lport_fcport_map even though there is no session yet
for the initiator. Since the only time we remove entries from this
map is when we free a session, this means that if we later delete this
node ACL without the initiator ever creating a session, we'll leave
the nacl pointer in the btree pointing at freed memory.
This is especially bad if that initiator later does send us a command
that would cause us to create a dynamic ACL and session: we'll find
the stale freed nacl pointer in the btree and end up with use-after-free.
We could add more code to clear the btree entry when deleting the
explicit nacl, but the original insertion is pointless: without a
session attached, we'll just have to update the entry when a session
appears anyway. So we can just delete tcm_qla2xxx_setup_nacl_from_rport()
and the code that calls it.
Signed-off-by: Roland Dreier <roland@purestorage.com>
Cc: Chad Dupuis <chad.dupuis@qlogic.com>
Cc: Giridhar Malavali <giridhar.malavali@qlogic.com>
Cc: Arun Easi <arun.easi@qlogic.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
| -rw-r--r-- | drivers/scsi/qla2xxx/tcm_qla2xxx.c | 73 |
1 files changed, 0 insertions, 73 deletions
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index a641c970569a..acc3b1151c4f 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c | |||
| @@ -762,65 +762,6 @@ static u16 tcm_qla2xxx_set_fabric_sense_len(struct se_cmd *se_cmd, | |||
| 762 | struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; | 762 | struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; |
| 763 | struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; | 763 | struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; |
| 764 | 764 | ||
| 765 | static int tcm_qla2xxx_setup_nacl_from_rport( | ||
| 766 | struct se_portal_group *se_tpg, | ||
| 767 | struct se_node_acl *se_nacl, | ||
| 768 | struct tcm_qla2xxx_lport *lport, | ||
| 769 | struct tcm_qla2xxx_nacl *nacl, | ||
| 770 | u64 rport_wwnn) | ||
| 771 | { | ||
| 772 | struct scsi_qla_host *vha = lport->qla_vha; | ||
| 773 | struct Scsi_Host *sh = vha->host; | ||
| 774 | struct fc_host_attrs *fc_host = shost_to_fc_host(sh); | ||
| 775 | struct fc_rport *rport; | ||
| 776 | unsigned long flags; | ||
| 777 | void *node; | ||
| 778 | int rc; | ||
| 779 | |||
| 780 | /* | ||
| 781 | * Scan the existing rports, and create a session for the | ||
| 782 | * explict NodeACL is an matching rport->node_name already | ||
| 783 | * exists. | ||
| 784 | */ | ||
| 785 | spin_lock_irqsave(sh->host_lock, flags); | ||
| 786 | list_for_each_entry(rport, &fc_host->rports, peers) { | ||
| 787 | if (rport_wwnn != rport->node_name) | ||
| 788 | continue; | ||
| 789 | |||
| 790 | pr_debug("Located existing rport_wwpn and rport->node_name: 0x%016LX, port_id: 0x%04x\n", | ||
| 791 | rport->node_name, rport->port_id); | ||
| 792 | nacl->nport_id = rport->port_id; | ||
| 793 | |||
| 794 | spin_unlock_irqrestore(sh->host_lock, flags); | ||
| 795 | |||
| 796 | spin_lock_irqsave(&vha->hw->hardware_lock, flags); | ||
| 797 | node = btree_lookup32(&lport->lport_fcport_map, rport->port_id); | ||
| 798 | if (node) { | ||
| 799 | rc = btree_update32(&lport->lport_fcport_map, | ||
| 800 | rport->port_id, se_nacl); | ||
| 801 | } else { | ||
| 802 | rc = btree_insert32(&lport->lport_fcport_map, | ||
| 803 | rport->port_id, se_nacl, | ||
| 804 | GFP_ATOMIC); | ||
| 805 | } | ||
| 806 | spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); | ||
| 807 | |||
| 808 | if (rc) { | ||
| 809 | pr_err("Unable to insert se_nacl into fcport_map"); | ||
| 810 | WARN_ON(rc > 0); | ||
| 811 | return rc; | ||
| 812 | } | ||
| 813 | |||
| 814 | pr_debug("Inserted into fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%08x\n", | ||
| 815 | se_nacl, rport_wwnn, nacl->nport_id); | ||
| 816 | |||
| 817 | return 1; | ||
| 818 | } | ||
| 819 | spin_unlock_irqrestore(sh->host_lock, flags); | ||
| 820 | |||
| 821 | return 0; | ||
| 822 | } | ||
| 823 | |||
| 824 | static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, | 765 | static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, |
| 825 | struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *); | 766 | struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *); |
| 826 | /* | 767 | /* |
| @@ -890,14 +831,10 @@ static struct se_node_acl *tcm_qla2xxx_make_nodeacl( | |||
| 890 | struct config_group *group, | 831 | struct config_group *group, |
| 891 | const char *name) | 832 | const char *name) |
| 892 | { | 833 | { |
| 893 | struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; | ||
| 894 | struct tcm_qla2xxx_lport *lport = container_of(se_wwn, | ||
| 895 | struct tcm_qla2xxx_lport, lport_wwn); | ||
| 896 | struct se_node_acl *se_nacl, *se_nacl_new; | 834 | struct se_node_acl *se_nacl, *se_nacl_new; |
| 897 | struct tcm_qla2xxx_nacl *nacl; | 835 | struct tcm_qla2xxx_nacl *nacl; |
| 898 | u64 wwnn; | 836 | u64 wwnn; |
| 899 | u32 qla2xxx_nexus_depth; | 837 | u32 qla2xxx_nexus_depth; |
| 900 | int rc; | ||
| 901 | 838 | ||
| 902 | if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) | 839 | if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) |
| 903 | return ERR_PTR(-EINVAL); | 840 | return ERR_PTR(-EINVAL); |
| @@ -924,16 +861,6 @@ static struct se_node_acl *tcm_qla2xxx_make_nodeacl( | |||
| 924 | nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); | 861 | nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); |
| 925 | nacl->nport_wwnn = wwnn; | 862 | nacl->nport_wwnn = wwnn; |
| 926 | tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); | 863 | tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); |
| 927 | /* | ||
| 928 | * Setup a se_nacl handle based on an a matching struct fc_rport setup | ||
| 929 | * via drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port() | ||
| 930 | */ | ||
| 931 | rc = tcm_qla2xxx_setup_nacl_from_rport(se_tpg, se_nacl, lport, | ||
| 932 | nacl, wwnn); | ||
| 933 | if (rc < 0) { | ||
| 934 | tcm_qla2xxx_release_fabric_acl(se_tpg, se_nacl_new); | ||
| 935 | return ERR_PTR(rc); | ||
| 936 | } | ||
| 937 | 864 | ||
| 938 | return se_nacl; | 865 | return se_nacl; |
| 939 | } | 866 | } |
