From: Yang Xiwen forbidden405@outlook.com
Original logic only sets the return value but doesn't jump out of the loop if the bus is kept active by a client. This is not expected. A malicious or buggy i2c client can hang the kernel in this case and should be avoided. This is observed during a long time test with a PCA953x GPIO extender.
Fix it by changing the logic to not only sets the return value, but also jumps out of the loop and return to the caller with -ETIMEDOUT.
Cc: stable@vger.kernel.org Signed-off-by: Yang Xiwen forbidden405@outlook.com --- drivers/i2c/busses/i2c-qup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3a36d682ed57..5b053e51f4c9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -452,8 +452,10 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) if (!(status & I2C_STATUS_BUS_ACTIVE)) break;
- if (time_after(jiffies, timeout)) + if (time_after(jiffies, timeout)) { ret = -ETIMEDOUT; + break; + }
usleep_range(len, len * 2); }
--- base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494 change-id: 20250615-qca-i2c-d41bb61aa59e
Best regards,
On 6/16/2025 12:01 AM, Yang Xiwen via B4 Relay wrote:
From: Yang Xiwen forbidden405@outlook.com
Original logic only sets the return value but doesn't jump out of the loop if the bus is kept active by a client. This is not expected. A malicious or buggy i2c client can hang the kernel in this case and should be avoided. This is observed during a long time test with a PCA953x GPIO extender.
Fix it by changing the logic to not only sets the return value, but also jumps out of the loop and return to the caller with -ETIMEDOUT.
Cc: stable@vger.kernel.org Signed-off-by: Yang Xiwen forbidden405@outlook.com
drivers/i2c/busses/i2c-qup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3a36d682ed57..5b053e51f4c9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -452,8 +452,10 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) if (!(status & I2C_STATUS_BUS_ACTIVE)) break;
if (time_after(jiffies, timeout))
if (time_after(jiffies, timeout)) { ret = -ETIMEDOUT;
break;
}
usleep_range(len, len * 2); }
base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494 change-id: 20250615-qca-i2c-d41bb61aa59e
Best regards,
Ping for review. The original logic error is very clear. This patch is also very small and can be reviewed in a short time.
If it insists on waiting for the bit to clear, it should not return -ETIMEDOUT then.
On 28-Jun-25 17:58, Yang Xiwen wrote:
On 6/16/2025 12:01 AM, Yang Xiwen via B4 Relay wrote:
From: Yang Xiwen forbidden405@outlook.com
Original logic only sets the return value but doesn't jump out of the loop if the bus is kept active by a client. This is not expected. A malicious or buggy i2c client can hang the kernel in this case and should be avoided. This is observed during a long time test with a PCA953x GPIO extender.
Fix it by changing the logic to not only sets the return value, but also jumps out of the loop and return to the caller with -ETIMEDOUT.
Cc: stable@vger.kernel.org Signed-off-by: Yang Xiwen forbidden405@outlook.com
drivers/i2c/busses/i2c-qup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3a36d682ed57..5b053e51f4c9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -452,8 +452,10 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) if (!(status & I2C_STATUS_BUS_ACTIVE)) break; - if (time_after(jiffies, timeout)) + if (time_after(jiffies, timeout)) { ret = -ETIMEDOUT; + break; + } usleep_range(len, len * 2); }
base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494 change-id: 20250615-qca-i2c-d41bb61aa59e
Best regards,
Ping for review. The original logic error is very clear. This patch is also very small and can be reviewed in a short time.
If it insists on waiting for the bit to clear, it should not return -ETIMEDOUT then.
'return -ETIMEDOUT' makes sense here, AFAICT
Konrad
On Mon, Jun 16, 2025 at 12:01:10AM +0800, Yang Xiwen via B4 Relay wrote:
From: Yang Xiwen forbidden405@outlook.com
Original logic only sets the return value but doesn't jump out of the loop if the bus is kept active by a client. This is not expected. A malicious or buggy i2c client can hang the kernel in this case and should be avoided. This is observed during a long time test with a PCA953x GPIO extender.
Fix it by changing the logic to not only sets the return value, but also jumps out of the loop and return to the caller with -ETIMEDOUT.
Cc: stable@vger.kernel.org Signed-off-by: Yang Xiwen forbidden405@outlook.com
I think you also need:
Fixes: fbfab1ab0658 ("i2c: qup: reorganization of driver code to remove polling for qup v1")
drivers/i2c/busses/i2c-qup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3a36d682ed57..5b053e51f4c9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -452,8 +452,10 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) if (!(status & I2C_STATUS_BUS_ACTIVE)) break;
if (time_after(jiffies, timeout))
if (time_after(jiffies, timeout)) { ret = -ETIMEDOUT;
break;
}
Well spotted Yang! I think this was the original idea, as well. Merged to i2c/i2c-host-fixes.
Andi
usleep_range(len, len * 2); }
base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494 change-id: 20250615-qca-i2c-d41bb61aa59e
Best regards,
Yang Xiwen forbidden405@outlook.com
linux-stable-mirror@lists.linaro.org