All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mayank Rungta" <mrungta@google.com>
Cc: linux-watchdog@vger.kernel.org
Subject: Re: [PATCH v2 3/5] genirq: Export NMI APIs
Date: Sat, 29 Aug 2026 01:15:50 +0000	[thread overview]
Message-ID: <20260829011550.ECF091F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260828-qcom-wdt-nmi-series-v2-3-363979fe6b6b@google.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Exporting `free_nmi()` and `disable_nmi()` allows loadable modules to manage NMIs, but these APIs fundamentally fail to synchronize with in-flight NMI handlers, introducing a race condition that leads to kernel panics on module unload.

Pre-existing issues:
- [High] `__cleanup_nmi()` fails to acquire `desc->request_mutex` when tearing down an NMI. This allows concurrent IRQ request/free operations to race, corrupting IRQ resource state and bypassing hardware resource allocation.
- [High] Concurrent NMI delivery during `free_nmi()` teardown leads to a NULL pointer dereference in `handle_fasteoi_nmi()` because `desc->action` is cleared before `__synchronize_hardirq()` waits for in-flight NMIs.
- [Medium] `free_nmi()` ignores the provided `dev_id` parameter, bypassing ownership validation and allowing any module to inadvertently or maliciously unregister an NMI owned by another subsystem.
--

commit cf44d4cc82f985321cdf77cbbbd3469b85de0426
Author: Mayank Rungta <mrungta@google.com>

genirq: Export NMI APIs

This commit exports request_nmi(), free_nmi(), enable_nmi(),
disable_nmi_nosync(), and disable_nmi() with EXPORT_SYMBOL_GPL to allow
loadable kernel modules to register and manage NMIs.

> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
> index 40013aa94481e..ded8cc33381cc 100644
> --- a/kernel/irq/manage.c
> +++ b/kernel/irq/manage.c

[ ... ]

> @@ -2110,6 +2113,7 @@ const void *free_nmi(unsigned int irq, void *dev_id)
>  
>  	return __cleanup_nmi(irq, desc);
>  }
> +EXPORT_SYMBOL_GPL(free_nmi);

[Severity: High]
Is it safe to export free_nmi() and disable_nmi() given they can introduce
a race condition that leads to kernel panics on module unload?

When a module unloads, free_nmi() calls __cleanup_nmi(), which uses
__synchronize_hardirq() to wait for handlers on other CPUs to finish.
__synchronize_hardirq() checks the IRQD_IRQ_INPROGRESS flag:

kernel/irq/manage.c:__synchronize_hardirq() {
    ...
		while (irqd_irq_inprogress(&desc->irq_data))
			cpu_relax();
    ...
}

However, NMI handlers like handle_fasteoi_nmi() bypass standard IRQ locking
and never set IRQD_IRQ_INPROGRESS:

kernel/irq/chip.c:handle_fasteoi_nmi() {
    ...
	res = action->handler(irq, action->dev_id);
    ...
}

Consequently, __synchronize_hardirq() returns immediately. The module's text
segment could then be unmapped while the NMI handler is still executing,
leading to a page fault.

[Severity: High]
This is a pre-existing issue, but can concurrent NMI delivery during
free_nmi() teardown lead to a NULL pointer dereference in
handle_fasteoi_nmi()?

During free_nmi(), __cleanup_nmi() sets desc->action = NULL and drops
desc->lock before calling __synchronize_hardirq():

kernel/irq/manage.c:__cleanup_nmi() {
    ...
	desc->action = NULL;

	irq_settings_clr_disable_unlazy(desc);
	irq_shutdown(desc);
    ...
	/* Ensure all in-flight NMI handlers on other CPUs complete before freeing action */
	__synchronize_hardirq(desc, true);
    ...
}

If an NMI fires concurrently, the dispatcher handle_fasteoi_nmi() executes
on another CPU without taking desc->lock. It reads desc->action and
unconditionally dereferences it without checking for NULL:

kernel/irq/chip.c:handle_fasteoi_nmi() {
    ...
	struct irqaction *action = desc->action;
    ...
	res = action->handler(irq, action->dev_id);
    ...
}

[Severity: High]
This isn't a bug introduced by this patch, but it appears __cleanup_nmi()
fails to acquire desc->request_mutex when tearing down an NMI. 

__cleanup_nmi() drops desc->lock and performs teardown (including
irq_release_resources()) without holding desc->request_mutex:

kernel/irq/manage.c:__cleanup_nmi() {
    ...
	irq_release_resources(desc);
    ...
}

Conversely, __setup_irq() relies exclusively on desc->request_mutex for
serialization. If __cleanup_nmi() runs concurrently with __setup_irq() (e.g.
during a rapid module reload or concurrent requests), they can race.
__setup_irq() may read a non-NULL desc->action and skip resource allocation:

kernel/irq/manage.c:__setup_irq() {
    ...
	if (!desc->action) {
		ret = irq_request_resources(desc);
    ...
}

Could this lead to bypassed hardware resource allocation or corrupted hardware
state for IRQ resources?

[Severity: Medium]
This is a pre-existing issue, but I noticed free_nmi() ignores the provided
dev_id parameter.

The free_nmi() API accepts a dev_id parameter, but delegates to
__cleanup_nmi() which drops the token entirely:

kernel/irq/manage.c:free_nmi() {
    ...
	return __cleanup_nmi(irq, desc);
}

Inside __cleanup_nmi(), the action is unconditionally unlinked and torn
down without checking if its dev_id matches the caller's cookie:

kernel/irq/manage.c:__cleanup_nmi() {
    ...
	if (!WARN_ON(desc->action == NULL)) {
		action = desc->action;
		irq_pm_remove_action(desc, action);
    ...
}

Unlike free_irq(), which verifies action->dev_id == dev_id, this lacks
ownership validation. Could a buggy loadable module unilaterally destroy
another component's NMI by passing an incorrect IRQ number or a
NULL cookie to free_nmi()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-qcom-wdt-nmi-series-v2-0-363979fe6b6b@google.com?part=3

  reply	other threads:[~2026-08-29  1:15 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-29  0:59 [PATCH v2 0/5] watchdog: qcom: Support NMI pretimeout warnings Mayank Rungta
2026-08-29  0:59 ` [PATCH v2 1/5] genirq: Synchronize in-flight handlers during NMI teardown Mayank Rungta
2026-08-29  1:14   ` sashiko-bot
2026-08-31 18:16   ` Doug Anderson
2026-08-29  0:59 ` [PATCH v2 2/5] genirq: Implement synchronous disable_nmi() Mayank Rungta
2026-08-29  1:18   ` sashiko-bot
2026-08-31 18:16   ` Doug Anderson
2026-08-29  0:59 ` [PATCH v2 3/5] genirq: Export NMI APIs Mayank Rungta
2026-08-29  1:15   ` sashiko-bot [this message]
2026-08-31 18:17   ` Doug Anderson
2026-08-29  0:59 ` [PATCH v2 4/5] watchdog: pretimeout: Protect governor access with RCU for NMI safety Mayank Rungta
2026-08-31 18:17   ` Doug Anderson
2026-08-29  0:59 ` [PATCH v2 5/5] watchdog: qcom: Register pretimeout interrupt as NMI Mayank Rungta
2026-08-29  1:15   ` sashiko-bot
2026-08-31 18:17   ` Doug Anderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260829011550.ECF091F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=mrungta@google.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.