Commit 07cc189d authored by Guenter Roeck's avatar Guenter Roeck

hwmon: (dme1737) Fix overflows seen when writing into limit attributes

Writes into voltage limit, temperature limit, temperature hysteresis,
and temperature zone attributes can overflow due to unclamped parameters
to multiplications, additions, and subtractions.

Cc: Juerg Haefliger <juergh@gmail.com>
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent 53e678d7
......@@ -279,7 +279,8 @@ static inline int IN_FROM_REG(int reg, int nominal, int res)
static inline int IN_TO_REG(long val, int nominal)
{
return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255);
val = clamp_val(val, 0, 255 * nominal / 192);
return DIV_ROUND_CLOSEST(val * 192, nominal);
}
/*
......@@ -295,7 +296,8 @@ static inline int TEMP_FROM_REG(int reg, int res)
static inline int TEMP_TO_REG(long val)
{
return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127);
val = clamp_val(val, -128000, 127000);
return DIV_ROUND_CLOSEST(val, 1000);
}
/* Temperature range */
......@@ -331,9 +333,10 @@ static inline int TEMP_HYST_FROM_REG(int reg, int ix)
return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
}
static inline int TEMP_HYST_TO_REG(long val, int ix, int reg)
static inline int TEMP_HYST_TO_REG(int temp, long hyst, int ix, int reg)
{
int hyst = clamp_val((val + 500) / 1000, 0, 15);
hyst = clamp_val(hyst, temp - 15000, temp);
hyst = DIV_ROUND_CLOSEST(temp - hyst, 1000);
return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
}
......@@ -1022,7 +1025,9 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
int ix = sensor_attr_2->index;
int fn = sensor_attr_2->nr;
long val;
int temp;
int err;
u8 reg;
err = kstrtol(buf, 10, &val);
if (err)
......@@ -1035,10 +1040,9 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
data->zone_low[ix] = dme1737_read(data,
DME1737_REG_ZONE_LOW(ix));
/* Modify the temp hyst value */
data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
TEMP_FROM_REG(data->zone_low[ix], 8) -
val, ix, dme1737_read(data,
DME1737_REG_ZONE_HYST(ix == 2)));
temp = TEMP_FROM_REG(data->zone_low[ix], 8);
reg = dme1737_read(data, DME1737_REG_ZONE_HYST(ix == 2));
data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(temp, val, ix, reg);
dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
data->zone_hyst[ix == 2]);
break;
......@@ -1055,10 +1059,10 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
* Modify the temp range value (which is stored in the upper
* nibble of the pwm_freq register)
*/
data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
TEMP_FROM_REG(data->zone_low[ix], 8),
dme1737_read(data,
DME1737_REG_PWM_FREQ(ix)));
temp = TEMP_FROM_REG(data->zone_low[ix], 8);
val = clamp_val(val, temp, temp + 80000);
reg = dme1737_read(data, DME1737_REG_PWM_FREQ(ix));
data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val - temp, reg);
dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
data->pwm_freq[ix]);
break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment