ptp_clock_adjtime() converts tx->freq to ppb with scaled_ppm_to_ppb() and rejects the request if it exceeds ops->max_adj. On 64-bit systems that conversion computes (1 + ppm) * 125 in s64, which can overflow for a large tx->freq and wrap the result back into [-max_adj, max_adj]. The check then passes and the original out-of-range value is handed to ->adjfine(). For example tx->freq = 147573952589676412 makes (1 + ppm) * 125 equal 2^64 + 9, which wraps to ppb == 0 and is accepted. Reject the request with -ERANGE if either the addition or the multiplication overflows. This hardens the max_adj sanity check and is not a security fix. It follows up commit 475b92f93216 ("ptp: improve max_adj check against unreasonable values"), which fixed the analogous s32 narrowing but not this overflow. Fixes: d39a743511cd ("ptp: validate the requested frequency adjustment.") Signed-off-by: Deep Shah --- drivers/ptp/ptp_clock.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index d6f54ccaf93b..f83aa44b0a74 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -159,7 +160,18 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) delta = ktime_to_ns(kt); err = ops->adjtime(ops, delta); } else if (tx->modes & ADJ_FREQUENCY) { - long ppb = scaled_ppm_to_ppb(tx->freq); + long ppb; + s64 tmp; + + /* + * scaled_ppm_to_ppb() multiplies (1 + freq) by 125 in s64; + * reject a ->freq large enough to overflow that, which could + * otherwise wrap the result back into the max_adj range. + */ + if (check_add_overflow(tx->freq, 1, &tmp) || + check_mul_overflow(tmp, 125, &tmp)) + return -ERANGE; + ppb = scaled_ppm_to_ppb(tx->freq); if (ppb > ops->max_adj || ppb < -ops->max_adj) return -ERANGE; err = ops->adjfine(ops, tx->freq); -- 2.43.0