mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	RDMA/iwcm: Fix a use-after-free related to destroying CM IDs
iw_conn_req_handler() associates a new struct rdma_id_private (conn_id) with
an existing struct iw_cm_id (cm_id) as follows:
        conn_id->cm_id.iw = cm_id;
        cm_id->context = conn_id;
        cm_id->cm_handler = cma_iw_handler;
rdma_destroy_id() frees both the cm_id and the struct rdma_id_private. Make
sure that cm_work_handler() does not trigger a use-after-free by only
freeing of the struct rdma_id_private after all pending work has finished.
Cc: stable@vger.kernel.org
Fixes: 59c68ac31e ("iw_cm: free cm_id resources on the last deref")
Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20240605145117.397751-6-bvanassche@acm.org
Signed-off-by: Leon Romanovsky <leon@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									a1babdb5b6
								
							
						
					
					
						commit
						aee2424246
					
				
					 1 changed files with 7 additions and 4 deletions
				
			
		| 
						 | 
					@ -368,8 +368,10 @@ EXPORT_SYMBOL(iw_cm_disconnect);
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Clean up all resources associated with the connection and release
 | 
					 * Clean up all resources associated with the connection and release
 | 
				
			||||||
 * the initial reference taken by iw_create_cm_id.
 | 
					 * the initial reference taken by iw_create_cm_id.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns true if and only if the last cm_id_priv reference has been dropped.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void destroy_cm_id(struct iw_cm_id *cm_id)
 | 
					static bool destroy_cm_id(struct iw_cm_id *cm_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct iwcm_id_private *cm_id_priv;
 | 
						struct iwcm_id_private *cm_id_priv;
 | 
				
			||||||
	struct ib_qp *qp;
 | 
						struct ib_qp *qp;
 | 
				
			||||||
| 
						 | 
					@ -439,7 +441,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
 | 
				
			||||||
		iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
 | 
							iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(void)iwcm_deref_id(cm_id_priv);
 | 
						return iwcm_deref_id(cm_id_priv);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -450,7 +452,8 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void iw_destroy_cm_id(struct iw_cm_id *cm_id)
 | 
					void iw_destroy_cm_id(struct iw_cm_id *cm_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	destroy_cm_id(cm_id);
 | 
						if (!destroy_cm_id(cm_id))
 | 
				
			||||||
 | 
							flush_workqueue(iwcm_wq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(iw_destroy_cm_id);
 | 
					EXPORT_SYMBOL(iw_destroy_cm_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1031,7 +1034,7 @@ static void cm_work_handler(struct work_struct *_work)
 | 
				
			||||||
		if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
 | 
							if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
 | 
				
			||||||
			ret = process_event(cm_id_priv, &levent);
 | 
								ret = process_event(cm_id_priv, &levent);
 | 
				
			||||||
			if (ret)
 | 
								if (ret)
 | 
				
			||||||
				destroy_cm_id(&cm_id_priv->id);
 | 
									WARN_ON_ONCE(destroy_cm_id(&cm_id_priv->id));
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			pr_debug("dropping event %d\n", levent.event);
 | 
								pr_debug("dropping event %d\n", levent.event);
 | 
				
			||||||
		if (iwcm_deref_id(cm_id_priv))
 | 
							if (iwcm_deref_id(cm_id_priv))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue