A use-after-free crash can occur after an ELS LOGO is aborted. Specifically, a nodelist structure is freed and then ndlp->vport->cfg_log_verbose is dereferenced in lpfc_nlp_get() when the discovery state machine is mistakenly called a second time with NLP_EVT_DEVICE_RM argument. Rework lpfc_cmpl_els_logo() to prevent the duplicate calls to release a nodelist structure.
Unified · Split
| @@ -2998,10 +2998,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, · 2997 unmodified lines | |||
| 2998 | ndlp->nlp_DID, ulp_status, | 2998 | ndlp->nlp_DID, ulp_status, |
| 2999 | ulp_word4); | 2999 | ulp_word4); |
| 3000 | 3000 | ||
| 3001 | /* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */ | ||
| 3002 | if (lpfc_error_lost_link(ulp_status, ulp_word4)) { | 3001 | if (lpfc_error_lost_link(ulp_status, ulp_word4)) { |
| 3003 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | ||
| 3004 | NLP_EVT_DEVICE_RM); | ||
| 3005 | skip_recovery = 1; | 3002 | skip_recovery = 1; |
| 3006 | goto out; | 3003 | goto out; |
| 3007 | } | 3004 | } |
| @@ -3021,18 +3018,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, · 13 unmodified lines | |||
| 3021 | spin_unlock_irq(&ndlp->lock); | 3018 | spin_unlock_irq(&ndlp->lock); |
| 3022 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 3019 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
| 3023 | NLP_EVT_DEVICE_RM); | 3020 | NLP_EVT_DEVICE_RM); |
| 3024 | lpfc_els_free_iocb(phba, cmdiocb); | 3021 | goto out_rsrc_free; |
| 3025 | lpfc_nlp_put(ndlp); | ||
| 3026 | |||
| 3027 | /* Presume the node was released. */ | ||
| 3028 | return; | ||
| 3029 | } | 3022 | } |
| 3030 | 3023 | ||
| 3031 | out: | 3024 | out: |
| 3032 | /* Driver is done with the IO. */ | ||
| 3033 | lpfc_els_free_iocb(phba, cmdiocb); | ||
| 3034 | lpfc_nlp_put(ndlp); | ||
| 3035 | |||
| 3036 | /* At this point, the LOGO processing is complete. NOTE: For a | 3025 | /* At this point, the LOGO processing is complete. NOTE: For a |
| 3037 | * pt2pt topology, we are assuming the NPortID will only change | 3026 | * pt2pt topology, we are assuming the NPortID will only change |
| 3038 | * on link up processing. For a LOGO / PLOGI initiated by the | 3027 | * on link up processing. For a LOGO / PLOGI initiated by the |
| @@ -3059,6 +3048,10 @@ out: · 20 unmodified lines | |||
| 3059 | ndlp->nlp_DID, ulp_status, | 3048 | ndlp->nlp_DID, ulp_status, |
| 3060 | ulp_word4, tmo, | 3049 | ulp_word4, tmo, |
| 3061 | vport->num_disc_nodes); | 3050 | vport->num_disc_nodes); |
| 3051 | |||
| 3052 | lpfc_els_free_iocb(phba, cmdiocb); | ||
| 3053 | lpfc_nlp_put(ndlp); | ||
| 3054 | |||
| 3062 | lpfc_disc_start(vport); | 3055 | lpfc_disc_start(vport); |
| 3063 | return; | 3056 | return; |
| 3064 | } | 3057 | } |
| @@ -3075,6 +3068,10 @@ out: · 10 unmodified lines | |||
| 3075 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 3068 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
| 3076 | NLP_EVT_DEVICE_RM); | 3069 | NLP_EVT_DEVICE_RM); |
| 3077 | } | 3070 | } |
| 3071 | out_rsrc_free: | ||
| 3072 | /* Driver is done with the I/O. */ | ||
| 3073 | lpfc_els_free_iocb(phba, cmdiocb); | ||
| 3074 | lpfc_nlp_put(ndlp); | ||
| 3078 | } | 3075 | } |
| 3079 | 3076 | ||
| 3080 | /** | 3077 | /** |