Re: [PATCH v3 4/4] firmware: stratix10-svc: Add for SDM mailbox doorbell interrupt

"NG, TZE YEE" <[email protected]>
Newsgroups org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Hi,

See my reply inline.

On 13/8/2026 2:51 pm, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] devm_request_any_context_irq() positive success values are incorrectly rejected by strict `ret == 0` check.
> - [High] Dropping trx_list_lock before callback execution allows client stack popping, leading to UAF/stack corruption.
> - [Medium] Improper handling of -EPROBE_DEFER from of_irq_get().
> --
> 
> --- Patch [4]: [PATCH v3 4/4] firmware: stratix10-svc: Add for SDM mailbox doorbell interrupt ---
> commit 0c0971a9e6fe55c0bfa458e38981b259f988e3ae
> Author: Mahesh Rao <[email protected]>
> 
> firmware: stratix10-svc: Add for SDM mailbox doorbell interrupt
> 
> Add support for SDM mailbox doorbell interrupt for async transactions. On
> interrupt, a workqueue is triggered which polls the ATF for pending responses
> and retrieves the bitmap of all retrieved and unprocessed transaction ids of
> mailbox responses from SDM. It then triggers the corresponding registered
> callbacks.
> 
>> diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
>> index f8c2da207cb4e..8c86441eae58b 100644
>> --- a/drivers/firmware/stratix10-svc.c
>> +++ b/drivers/firmware/stratix10-svc.c
> 
> [ ... ]
> 
>> @@ -1659,14 +1666,96 @@ static inline void stratix10_smc_1_2(struct stratix10_async_ctrl *actrl,
>>   	arm_smccc_1_2_smc(args, res);
>>   }
>>   
> [ ... ]
>> +static void stratix10_async_workqueue_handler(struct work_struct *work)
>> +{
> [ ... ]
>> +		do {
>> +			transaction_id = find_next_bit(pend_on_irq,
>> +						       TOTAL_TRANSACTION_IDS,
>> +						       transaction_id);
>> +			if (transaction_id >= TOTAL_TRANSACTION_IDS)
>> +				break;
>> +
>> +			cb = NULL;
>> +			cb_arg = NULL;
>> +			spin_lock(&actrl->trx_list_lock);
>> +			hash_for_each_possible(actrl->trx_list, handler,
>> +					       next, transaction_id) {
>> +				if (handler->transaction_id == transaction_id) {
>> +					cb = handler->cb;
>> +					cb_arg = handler->cb_arg;
>> +					break;
>> +				}
>> +			}
>> +			spin_unlock(&actrl->trx_list_lock);
>> +			if (cb)
>> +				cb(cb_arg);
> 
> [Severity: High]
> Is there a risk of stack corruption or a use-after-free here?
> 
> By executing the callback after dropping trx_list_lock, a racing client
> timeout might execute stratix10_svc_async_done() and delete the handler.
> 
> This could result in popping the client stack before the workqueue executes
> the callback on the now-invalid stack address cb_arg. Should the lock be held
> during the callback or is there another way to ensure cb_arg remains valid?

Agreed. We copy cb/cb_arg under the lock (so the handler itself is 
safe), but a client that times out and calls stratix10_svc_async_done() 
on another CPU can still free cb_arg before the callback runs.

Since callbacks run in BH context (system_bh_wq) and are already atomic, 
we can simply invoke the callback under the lock so async_done() waits 
for it to finish:

scoped_guard(spinlock, &actrl->trx_list_lock) {
	hash_for_each_possible(actrl->trx_list, handler,
		next, transaction_id) {
	if (handler->transaction_id == transaction_id) {
		if (handler->cb)
			handler->cb(handler->cb_arg);
		break;
		}
	}
}

The only constraint is that a callback must not call back into 
async_send()/async_done() (same lock). Does this approach look good to you?

> 
>> +
>> +			transaction_id++;
>> +		} while (transaction_id < TOTAL_TRANSACTION_IDS);
>> +	}
>> +	enable_irq(actrl->irq);
>> +}
> 
> [ ... ]
> 
>> @@ -1727,6 +1816,22 @@ static int stratix10_svc_async_init(struct stratix10_svc_controller *controller)
>>   	hash_init(actrl->trx_list);
>>   	atomic_set(&actrl->common_achan_refcount, 0);
>>   
>> +	irq = of_irq_get(dev_of_node(dev), 0);
>> +	if (irq <= 0) {
> 
> [Severity: Medium]
> Does this improperly swallow -EPROBE_DEFER?
> 
> Because of_irq_get() can return -EPROBE_DEFER as a negative value,
> this check will convert the probe deferral into a permanent fallback
> to polling mode. Should this propagate -EPROBE_DEFER instead?
> 

Agreed. The parent here is the GIC (initialized early), so it shouldn't 
defer in practice, but propagating it is more correct:

irq = of_irq_get(dev_of_node(dev), 0);
if (irq == -EPROBE_DEFER) {
	ida_destroy(&actrl->async_id_pool);
	actrl->invoke_fn = NULL;
	return -EPROBE_DEFER;
}
if (irq <= 0) {
	dev_warn(dev, "Failed to get IRQ, falling back to polling mode\n");
} else {
	...
}

Since the IRQ is optional (polling is a valid fallback), do you want us 
to propagate -EPROBE_DEFER, or just keep the polling fallback on any 
failure?

>> +		dev_warn(dev, "Failed to get IRQ, falling back to polling mode\n");
>> +	} else {
>> +		ret = devm_request_any_context_irq(dev, irq, stratix10_svc_async_irq_handler,
>> +						   IRQF_NO_AUTOEN, "stratix10_svc", controller);
>> +		if (ret == 0) {
> 
> [Severity: High]
> Will this correctly handle nested IRQs?
> 
> devm_request_any_context_irq() returns IRQC_IS_NESTED (which is 1) on success
> for nested IRQs.
> 
> By strictly checking for ret == 0, successful nested IRQ assignments will
> be rejected. This skips INIT_WORK and enable_irq(), leaving the registered IRQ
> permanently disabled and causing asynchronous transactions to time out.
> Should this check for ret >= 0 instead?
> 

devm_request_any_context_irq() returns 0 (hard IRQ) or 1 (nested) on 
success. On our devices the SDM doorbell is a normal GIC SPI (hard IRQ), 
so ret == 0 is always correct here and never nested. ret >= 0 would be 
the more idiomatic check.

Do you prefer we keep ret == 0, or switch to ret >= 0?

Thanks,
Tze Yee

>> +			dev_info(dev,
>> +				 "Registered IRQ %d for sip async operations\n",
>> +				 irq);
>> +			actrl->irq = irq;
>> +			INIT_WORK(&actrl->async_work, stratix10_async_workqueue_handler);
>> +			enable_irq(actrl->irq);
>> +		}
>> +	}
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.