Skip to content

Commit 579b86f

Browse files
committed
hwmon: (macsmc) Fix overflows, underflows, and sign extension
The macsmc-hwmon driver experienced several issues related to value scaling and type conversion: 1. macsmc_hwmon_read_f32_scaled() clipped values to INT_MAX/INT_MIN. On 64-bit systems, hwmon supports long values, so clipping to 32-bit range was premature and caused loss of range for high-power sensors. Changed it to use long and clip to LONG_MAX/LONG_MIN. 2. The overflow check in macsmc_hwmon_read_f32_scaled() used 1UL, which is 32-bit on some platforms. Switched to 1ULL. 3. macsmc_hwmon_read_key() used a u32 temporary variable for f32 values. When assigned to a 64-bit long, negative values were zero-extended instead of sign-extended, resulting in large positive numbers. 4. macsmc_hwmon_read_ioft_scaled() used mult_frac() which could overflow during intermediate multiplication. Switched to mul_u64_u32_div() to handle the 64-bit multiplication safely. 5. ioft values (unsigned 48.16) could overflow long when scaled by 1,000,000. Added explicit clipping to LONG_MAX in the caller. 6. macsmc_hwmon_write_f32() truncated its long argument to int, potentially causing issues for large values. Fix these issues by using appropriate types and helper functions. Fixes: 785205f ("hwmon: Add Apple Silicon SMC hwmon driver") Cc: James Calligeros <jcalligeros99@gmail.com> Cc: Nathan Chancellor <nathan@kernel.org> Cc: Neal Gompa <neal@gompa.dev> Cc: Janne Grunau <j@jannau.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20260129175112.3751907-3-linux@roeck-us.net Reviewed-by: James Calligeros <jcalligeros99@gmail.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent 5dd69b8 commit 579b86f

1 file changed

Lines changed: 16 additions & 12 deletions

File tree

drivers/hwmon/macsmc-hwmon.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <linux/bitfield.h>
2424
#include <linux/hwmon.h>
25+
#include <linux/math64.h>
2526
#include <linux/mfd/macsmc.h>
2627
#include <linux/module.h>
2728
#include <linux/of.h>
@@ -130,7 +131,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
130131
if (ret < 0)
131132
return ret;
132133

133-
*p = mult_frac(val, scale, 65536);
134+
*p = mul_u64_u32_div(val, scale, 65536);
134135

135136
return 0;
136137
}
@@ -140,7 +141,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
140141
* them.
141142
*/
142143
static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
143-
int *p, int scale)
144+
long *p, int scale)
144145
{
145146
u32 fval;
146147
u64 val;
@@ -162,21 +163,21 @@ static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
162163
val = 0;
163164
else if (exp < 0)
164165
val >>= -exp;
165-
else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
166+
else if (exp != 0 && (val & ~((1ULL << (64 - exp)) - 1))) /* overflow */
166167
val = U64_MAX;
167168
else
168169
val <<= exp;
169170

170171
if (fval & FLT_SIGN_MASK) {
171-
if (val > (-(s64)INT_MIN))
172-
*p = INT_MIN;
172+
if (val > (u64)LONG_MAX + 1)
173+
*p = LONG_MIN;
173174
else
174-
*p = -val;
175+
*p = -(long)val;
175176
} else {
176-
if (val > INT_MAX)
177-
*p = INT_MAX;
177+
if (val > (u64)LONG_MAX)
178+
*p = LONG_MAX;
178179
else
179-
*p = val;
180+
*p = (long)val;
180181
}
181182

182183
return 0;
@@ -195,7 +196,7 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
195196
switch (sensor->info.type_code) {
196197
/* 32-bit IEEE 754 float */
197198
case __SMC_KEY('f', 'l', 't', ' '): {
198-
u32 flt_ = 0;
199+
long flt_ = 0;
199200

200201
ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
201202
&flt_, scale);
@@ -214,7 +215,10 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
214215
if (ret)
215216
return ret;
216217

217-
*val = (long)ioft;
218+
if (ioft > LONG_MAX)
219+
*val = LONG_MAX;
220+
else
221+
*val = (long)ioft;
218222
break;
219223
}
220224
default:
@@ -224,7 +228,7 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
224228
return 0;
225229
}
226230

227-
static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value)
231+
static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, long value)
228232
{
229233
u64 val;
230234
u32 fval = 0;

0 commit comments

Comments
 (0)