[PATCH] ppdev: prevent overflow when setting port timeout

Linmao Li posted 1 patch 1 week, 2 days ago
drivers/char/ppdev.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
[PATCH] ppdev: prevent overflow when setting port timeout
Posted by Linmao Li 1 week, 2 days ago
PPSETTIME64 supplies the timeval fields as s64 values, but
pp_set_timeout() narrows tv_usec to int and calculates tv_sec * HZ in a
signed long. Large positive values can therefore be truncated or overflow
and install an unintended timeout.

Keep both fields as s64, reject a non-canonical microsecond value, and
use timespec64_to_jiffies() to cap excessively large timeouts at
MAX_JIFFY_OFFSET. This is a behavior change because both PPSETTIME
ioctls could previously accept values with tv_usec >= USEC_PER_SEC.
The validation follows the precedent set by sock_set_timeout().

Fixes: 3b9ab374a1e6 ("ppdev: convert to y2038 safe")
Signed-off-by: Linmao Li <lilinmao@kylinos.cn>
---
 drivers/char/ppdev.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 6da817b9849f..8803268b4cdc 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -340,15 +340,17 @@ static enum ieee1284_phase init_phase(int mode)
 	return IEEE1284_PH_FWD_IDLE;
 }
 
-static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec)
+static int pp_set_timeout(struct pardevice *pdev, s64 tv_sec, s64 tv_usec)
 {
+	struct timespec64 ts;
 	long to_jiffies;
 
-	if ((tv_sec < 0) || (tv_usec < 0))
+	if (tv_sec < 0 || tv_usec < 0 || tv_usec >= USEC_PER_SEC)
 		return -EINVAL;
 
-	to_jiffies = usecs_to_jiffies(tv_usec);
-	to_jiffies += tv_sec * HZ;
+	ts.tv_sec = tv_sec;
+	ts.tv_nsec = tv_usec * NSEC_PER_USEC;
+	to_jiffies = timespec64_to_jiffies(&ts);
 	if (to_jiffies <= 0)
 		return -EINVAL;
 
-- 
2.25.1
Re: [PATCH] ppdev: prevent overflow when setting port timeout
Posted by Arnd Bergmann 1 week, 2 days ago
On Thu, Jul 16, 2026, at 03:39, Linmao Li wrote:
> PPSETTIME64 supplies the timeval fields as s64 values, but
> pp_set_timeout() narrows tv_usec to int and calculates tv_sec * HZ in a
> signed long. Large positive values can therefore be truncated or overflow
> and install an unintended timeout.
>
> Keep both fields as s64, reject a non-canonical microsecond value, and
> use timespec64_to_jiffies() to cap excessively large timeouts at
> MAX_JIFFY_OFFSET. This is a behavior change because both PPSETTIME
> ioctls could previously accept values with tv_usec >= USEC_PER_SEC.
> The validation follows the precedent set by sock_set_timeout().
>
> Fixes: 3b9ab374a1e6 ("ppdev: convert to y2038 safe")
> Signed-off-by: Linmao Li <lilinmao@kylinos.cn>

Good catch!

> -	to_jiffies = usecs_to_jiffies(tv_usec);
> -	to_jiffies += tv_sec * HZ;
> +	ts.tv_sec = tv_sec;
> +	ts.tv_nsec = tv_usec * NSEC_PER_USEC;
> +	to_jiffies = timespec64_to_jiffies(&ts);
>  	if (to_jiffies <= 0)
>  		return -EINVAL;

This is a bit more expensive, but it's clearly not performance
critical and I agree that the added range checking is a
nice improvement here.

I also checked codesearch.debian.net to see if any callers
might rely on passing out-of-range arguments, but the only
caller I found (pyparallel) is guaranteed to pass a
normalized timeval.

Reviewed-by: Arnd Bergmann <arnd@arndb.de>