Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d9bc6d6 authored by Ralph Campbell's avatar Ralph Campbell Committed by Roland Dreier
Browse files

IB/mad: Fix null pointer dereference in local_completions()



handle_outgoing_dr_smp() can queue a struct ib_mad_local_private
*local on the mad_agent_priv->local_work work queue with
local->mad_priv == NULL if device->process_mad() returns
IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY and
(!ib_response_mad(&mad_priv->mad.mad) ||
!mad_agent_priv->agent.recv_handler).

In this case, local_completions() will be called with local->mad_priv
== NULL. The code does check for this case and skips calling
recv_mad_agent->agent.recv_handler() but recv == 0 so
kmem_cache_free() is called with a NULL pointer.

Also, since recv isn't reinitialized each time through the loop, it
can cause a memory leak if recv should have been zero.

Signed-off-by: default avatarRalph Campbell <ralph.campbell@qlogic.com>
parent 7020cb0f
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -2356,7 +2356,7 @@ static void local_completions(struct work_struct *work)
	struct ib_mad_local_private *local;
	struct ib_mad_agent_private *recv_mad_agent;
	unsigned long flags;
	int recv = 0;
	int free_mad;
	struct ib_wc wc;
	struct ib_mad_send_wc mad_send_wc;

@@ -2370,14 +2370,15 @@ static void local_completions(struct work_struct *work)
				   completion_list);
		list_del(&local->completion_list);
		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
		free_mad = 0;
		if (local->mad_priv) {
			recv_mad_agent = local->recv_mad_agent;
			if (!recv_mad_agent) {
				printk(KERN_ERR PFX "No receive MAD agent for local completion\n");
				free_mad = 1;
				goto local_send_completion;
			}

			recv = 1;
			/*
			 * Defined behavior is to complete response
			 * before request
@@ -2422,7 +2423,7 @@ local_send_completion:

		spin_lock_irqsave(&mad_agent_priv->lock, flags);
		atomic_dec(&mad_agent_priv->refcount);
		if (!recv)
		if (free_mad)
			kmem_cache_free(ib_mad_cache, local->mad_priv);
		kfree(local);
	}