[PATCH v2] i2c: i801: fix hardware state machine corruption in error path

w15303746062@163.com posted 1 patch 1 month ago
drivers/i2c/busses/i2c-i801.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH v2] i2c: i801: fix hardware state machine corruption in error path
Posted by w15303746062@163.com 1 month ago
From: Mingyu Wang <25181214217@stu.xidian.edu.cn>

A severe livelock and subsequent Hung Task panic were observed in the
i2c-i801 driver during concurrent Fuzzing. The crash is caused by an
unconditional hardware register cleanup in the error handling path of
i801_access().

When i801_check_pre() fails (e.g., returning -EBUSY because the SMBus
controller is actively used by BIOS/ACPI), the kernel does not actually
acquire the hardware ownership. However, the code jumps to the 'out'
label and executes:

    iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));

This forcefully clears the INUSE_STS lock and resets the hardware status
flags without owning the controller. Doing so interrupts ongoing BIOS/ACPI
transactions and totally corrupts the SMBus hardware state machine.

Consequently, all subsequent i801_access() calls fail at the pre-check
stage, triggering an endless stream of "SMBus is busy, can't use it!"
error logs. Over a slow serial console, this printk flood monopolizes
the CPU (Console Livelock), starving other processes trying to acquire
the mmap_lock down_read semaphore, ultimately triggering the hung task
watchdog.

Fix this by moving the 'out' label below the hardware register cleanup.
If i801_check_pre() fails, we safely bypass the iowrite8() and only
release the software locks (pm_runtime and mutex), strictly adhering to
the rule of not releasing resources that were never acquired.

Fixes: 1f760b87e54c ("i2c: i801: Call i801_check_pre() from i801_access()")
Cc: stable@vger.kernel.org # v6.3+

Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
Changes in v2:
 - Reused and moved the existing 'out' label instead of adding a new one,
   fixing a build warning regarding an unused label.
 - Dropped the inaccurate mention of "another thread" in the commit message,
   as i801_access() is serialized by a mutex.
 - Added Fixes and Cc stable tags as suggested.

 drivers/i2c/busses/i2c-i801.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 32a3cef02c7b..b29c99ed3883 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -931,13 +931,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
 	 */
 	if (hwpec)
 		iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
-out:
 	/*
 	 * Unlock the SMBus device for use by BIOS/ACPI,
 	 * and clear status flags if not done already.
 	 */
 	iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
 
+out:
 	pm_runtime_put_autosuspend(&priv->pci_dev->dev);
 	mutex_unlock(&priv->acpi_lock);
 	return ret;
-- 
2.34.1
Re: [PATCH v2] i2c: i801: fix hardware state machine corruption in error path
Posted by Andi Shyti 4 days, 1 hour ago
Hi Jean,

could you please take a look here?

Thanks,
Andi

On Tue, May 12, 2026 at 05:35:34PM +0800, w15303746062@163.com wrote:
> From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
> 
> A severe livelock and subsequent Hung Task panic were observed in the
> i2c-i801 driver during concurrent Fuzzing. The crash is caused by an
> unconditional hardware register cleanup in the error handling path of
> i801_access().
> 
> When i801_check_pre() fails (e.g., returning -EBUSY because the SMBus
> controller is actively used by BIOS/ACPI), the kernel does not actually
> acquire the hardware ownership. However, the code jumps to the 'out'
> label and executes:
> 
>     iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
> 
> This forcefully clears the INUSE_STS lock and resets the hardware status
> flags without owning the controller. Doing so interrupts ongoing BIOS/ACPI
> transactions and totally corrupts the SMBus hardware state machine.
> 
> Consequently, all subsequent i801_access() calls fail at the pre-check
> stage, triggering an endless stream of "SMBus is busy, can't use it!"
> error logs. Over a slow serial console, this printk flood monopolizes
> the CPU (Console Livelock), starving other processes trying to acquire
> the mmap_lock down_read semaphore, ultimately triggering the hung task
> watchdog.
> 
> Fix this by moving the 'out' label below the hardware register cleanup.
> If i801_check_pre() fails, we safely bypass the iowrite8() and only
> release the software locks (pm_runtime and mutex), strictly adhering to
> the rule of not releasing resources that were never acquired.
> 
> Fixes: 1f760b87e54c ("i2c: i801: Call i801_check_pre() from i801_access()")
> Cc: stable@vger.kernel.org # v6.3+
> 
> Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
> ---
> Changes in v2:
>  - Reused and moved the existing 'out' label instead of adding a new one,
>    fixing a build warning regarding an unused label.
>  - Dropped the inaccurate mention of "another thread" in the commit message,
>    as i801_access() is serialized by a mutex.
>  - Added Fixes and Cc stable tags as suggested.
> 
>  drivers/i2c/busses/i2c-i801.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
> index 32a3cef02c7b..b29c99ed3883 100644
> --- a/drivers/i2c/busses/i2c-i801.c
> +++ b/drivers/i2c/busses/i2c-i801.c
> @@ -931,13 +931,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
>  	 */
>  	if (hwpec)
>  		iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
> -out:
>  	/*
>  	 * Unlock the SMBus device for use by BIOS/ACPI,
>  	 * and clear status flags if not done already.
>  	 */
>  	iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
>  
> +out:
>  	pm_runtime_put_autosuspend(&priv->pci_dev->dev);
>  	mutex_unlock(&priv->acpi_lock);
>  	return ret;
> -- 
> 2.34.1
>
Re:[PATCH v2] i2c: i801: fix hardware state machine corruption in error path
Posted by w15303746062 1 week, 1 day ago

Hi Jean, Andi,

Just a gentle ping on this v2 patch. It reuses the existing 'out' label to fix 
the unused label warning and updates the commit message exactly as Jean suggested.

Please let me know if there is anything else needed from my side, or if 
it is good to be queued up.

Thanks,
Mingyu

At 2026-05-12 17:35:34, w15303746062@163.com wrote:
>From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
>
>A severe livelock and subsequent Hung Task panic were observed in the
>i2c-i801 driver during concurrent Fuzzing. The crash is caused by an
>unconditional hardware register cleanup in the error handling path of
>i801_access().
>
>When i801_check_pre() fails (e.g., returning -EBUSY because the SMBus
>controller is actively used by BIOS/ACPI), the kernel does not actually
>acquire the hardware ownership. However, the code jumps to the 'out'
>label and executes:
>
>    iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
>
>This forcefully clears the INUSE_STS lock and resets the hardware status
>flags without owning the controller. Doing so interrupts ongoing BIOS/ACPI
>transactions and totally corrupts the SMBus hardware state machine.
>
>Consequently, all subsequent i801_access() calls fail at the pre-check
>stage, triggering an endless stream of "SMBus is busy, can't use it!"
>error logs. Over a slow serial console, this printk flood monopolizes
>the CPU (Console Livelock), starving other processes trying to acquire
>the mmap_lock down_read semaphore, ultimately triggering the hung task
>watchdog.
>
>Fix this by moving the 'out' label below the hardware register cleanup.
>If i801_check_pre() fails, we safely bypass the iowrite8() and only
>release the software locks (pm_runtime and mutex), strictly adhering to
>the rule of not releasing resources that were never acquired.
>
>Fixes: 1f760b87e54c ("i2c: i801: Call i801_check_pre() from i801_access()")
>Cc: stable@vger.kernel.org # v6.3+
>
>Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
>---
>Changes in v2:
> - Reused and moved the existing 'out' label instead of adding a new one,
>   fixing a build warning regarding an unused label.
> - Dropped the inaccurate mention of "another thread" in the commit message,
>   as i801_access() is serialized by a mutex.
> - Added Fixes and Cc stable tags as suggested.
>
> drivers/i2c/busses/i2c-i801.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
>diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
>index 32a3cef02c7b..b29c99ed3883 100644
>--- a/drivers/i2c/busses/i2c-i801.c
>+++ b/drivers/i2c/busses/i2c-i801.c
>@@ -931,13 +931,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
> 	 */
> 	if (hwpec)
> 		iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
>-out:
> 	/*
> 	 * Unlock the SMBus device for use by BIOS/ACPI,
> 	 * and clear status flags if not done already.
> 	 */
> 	iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
> 
>+out:
> 	pm_runtime_put_autosuspend(&priv->pci_dev->dev);
> 	mutex_unlock(&priv->acpi_lock);
> 	return ret;
>-- 
>2.34.1