linux-hwmon.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data
@ 2021-04-09 17:48 Guenter Roeck
  2021-04-09 17:48 ` [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters Guenter Roeck
  2021-04-12 12:14 ` [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Jean Delvare
  0 siblings, 2 replies; 8+ messages in thread
From: Guenter Roeck @ 2021-04-09 17:48 UTC (permalink / raw)
  To: Hardware Monitoring
  Cc: Jean Delvare, Guenter Roeck, Naveen Krishna Chatradhi,
	Greg Kroah-Hartman

The driver implements two separate functions to read and update
energy values. One function is called periodically and updates
cached enery information to avoid loss of data, the other reads
energy data on demand to report it to userspace. The second
function reads current energy data, adds the difference to the
data previously obtained by the first function, and then discards
the updated data.

Simplify the code and always call the first function, then report
the energy data obtained by this function to userspace.

Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v2: Added patch, simplification

 drivers/hwmon/amd_energy.c | 31 ++++++-------------------------
 1 file changed, 6 insertions(+), 25 deletions(-)

diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
index a86cc8d6d93d..93bad64039f1 100644
--- a/drivers/hwmon/amd_energy.c
+++ b/drivers/hwmon/amd_energy.c
@@ -118,35 +118,12 @@ static void read_accumulate(struct amd_energy_data *data)
 	data->core_id++;
 }
 
-static void amd_add_delta(struct amd_energy_data *data, int ch,
-			  int cpu, long *val, u32 reg)
-{
-	struct sensor_accumulator *accum;
-	u64 input;
-
-	mutex_lock(&data->lock);
-	rdmsrl_safe_on_cpu(cpu, reg, &input);
-	input &= AMD_ENERGY_MASK;
-
-	accum = &data->accums[ch];
-	if (input >= accum->prev_value)
-		input += accum->energy_ctr -
-				accum->prev_value;
-	else
-		input += UINT_MAX - accum->prev_value +
-				accum->energy_ctr;
-
-	/* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */
-	*val = div64_ul(input * 1000000UL, BIT(data->energy_units));
-
-	mutex_unlock(&data->lock);
-}
-
 static int amd_energy_read(struct device *dev,
 			   enum hwmon_sensor_types type,
 			   u32 attr, int channel, long *val)
 {
 	struct amd_energy_data *data = dev_get_drvdata(dev);
+	struct sensor_accumulator *accum;
 	u32 reg;
 	int cpu;
 
@@ -162,7 +139,11 @@ static int amd_energy_read(struct device *dev,
 
 		reg = ENERGY_CORE_MSR;
 	}
-	amd_add_delta(data, channel, cpu, val, reg);
+
+	accumulate_delta(data, channel, cpu, reg);
+	accum = &data->accums[channel];
+
+	*val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
 
 	return 0;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters
  2021-04-09 17:48 [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Guenter Roeck
@ 2021-04-09 17:48 ` Guenter Roeck
  2021-04-12 12:27   ` Jean Delvare
  2021-04-12 12:14 ` [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Jean Delvare
  1 sibling, 1 reply; 8+ messages in thread
From: Guenter Roeck @ 2021-04-09 17:48 UTC (permalink / raw)
  To: Hardware Monitoring
  Cc: Jean Delvare, Guenter Roeck, Naveen Krishna Chatradhi,
	Greg Kroah-Hartman

Commit 60268b0e8258 ("hwmon: (amd_energy) modify the visibility of
the counters") restricted visibility of AMD energy counters to work
around a side-channel attack using energy data to determine which
instructions are executed. The attack is described in 'PLATYPUS:
Software-based Power Side-Channel Attacks on x86'. It relies on quick
and accurate energy readings.

Limiting energy readings to privileged users is annoying. A much better
solution is to make energy readings unusable for attacks by randomizing
the time between updates. We can do that by caching energy values for
a short and randomized period of time.

Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v2: Simplified code by using unified function to accumulate energy data

 drivers/hwmon/amd_energy.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
index 93bad64039f1..1bf0afc2740c 100644
--- a/drivers/hwmon/amd_energy.c
+++ b/drivers/hwmon/amd_energy.c
@@ -18,6 +18,7 @@
 #include <linux/mutex.h>
 #include <linux/processor.h>
 #include <linux/platform_device.h>
+#include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/topology.h>
@@ -35,6 +36,7 @@
 struct sensor_accumulator {
 	u64 energy_ctr;
 	u64 prev_value;
+	unsigned long cache_timeout;
 };
 
 struct amd_energy_data {
@@ -74,17 +76,14 @@ static void get_energy_units(struct amd_energy_data *data)
 	data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;
 }
 
-static void accumulate_delta(struct amd_energy_data *data,
-			     int channel, int cpu, u32 reg)
+static void __accumulate_delta(struct sensor_accumulator *accum,
+			       int cpu, u32 reg)
 {
-	struct sensor_accumulator *accum;
 	u64 input;
 
-	mutex_lock(&data->lock);
 	rdmsrl_safe_on_cpu(cpu, reg, &input);
 	input &= AMD_ENERGY_MASK;
 
-	accum = &data->accums[channel];
 	if (input >= accum->prev_value)
 		accum->energy_ctr +=
 			input - accum->prev_value;
@@ -93,6 +92,14 @@ static void accumulate_delta(struct amd_energy_data *data,
 			accum->prev_value + input;
 
 	accum->prev_value = input;
+	accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;
+}
+
+static void accumulate_delta(struct amd_energy_data *data,
+			     int channel, int cpu, u32 reg)
+{
+	mutex_lock(&data->lock);
+	__accumulate_delta(&data->accums[channel], cpu, reg);
 	mutex_unlock(&data->lock);
 }
 
@@ -124,6 +131,7 @@ static int amd_energy_read(struct device *dev,
 {
 	struct amd_energy_data *data = dev_get_drvdata(dev);
 	struct sensor_accumulator *accum;
+	u64 energy;
 	u32 reg;
 	int cpu;
 
@@ -140,10 +148,15 @@ static int amd_energy_read(struct device *dev,
 		reg = ENERGY_CORE_MSR;
 	}
 
-	accumulate_delta(data, channel, cpu, reg);
 	accum = &data->accums[channel];
 
-	*val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
+	mutex_lock(&data->lock);
+	if (!accum->energy_ctr || time_after(jiffies, accum->cache_timeout))
+		__accumulate_delta(accum, cpu, reg);
+	energy = accum->energy_ctr;
+	mutex_unlock(&data->lock);
+
+	*val = div64_ul(energy * 1000000UL, BIT(data->energy_units));
 
 	return 0;
 }
@@ -152,7 +165,7 @@ static umode_t amd_energy_is_visible(const void *_data,
 				     enum hwmon_sensor_types type,
 				     u32 attr, int channel)
 {
-	return 0440;
+	return 0444;
 }
 
 static int energy_accumulator(void *p)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data
  2021-04-09 17:48 [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Guenter Roeck
  2021-04-09 17:48 ` [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters Guenter Roeck
@ 2021-04-12 12:14 ` Jean Delvare
  2021-04-12 14:17   ` Guenter Roeck
  1 sibling, 1 reply; 8+ messages in thread
From: Jean Delvare @ 2021-04-12 12:14 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Hardware Monitoring, Naveen Krishna Chatradhi, Greg Kroah-Hartman

Hi Guenter,

On Fri,  9 Apr 2021 10:48:51 -0700, Guenter Roeck wrote:
> The driver implements two separate functions to read and update
> energy values. One function is called periodically and updates
> cached enery information to avoid loss of data, the other reads
> energy data on demand to report it to userspace. The second
> function reads current energy data, adds the difference to the
> data previously obtained by the first function, and then discards
> the updated data.
> 
> Simplify the code and always call the first function, then report
> the energy data obtained by this function to userspace.

I like the idea.

> Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> ---
> v2: Added patch, simplification
> 
>  drivers/hwmon/amd_energy.c | 31 ++++++-------------------------
>  1 file changed, 6 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
> index a86cc8d6d93d..93bad64039f1 100644
> --- a/drivers/hwmon/amd_energy.c
> +++ b/drivers/hwmon/amd_energy.c
> @@ -118,35 +118,12 @@ static void read_accumulate(struct amd_energy_data *data)
>  	data->core_id++;
>  }
>  
> -static void amd_add_delta(struct amd_energy_data *data, int ch,
> -			  int cpu, long *val, u32 reg)
> -{
> -	struct sensor_accumulator *accum;
> -	u64 input;
> -
> -	mutex_lock(&data->lock);
> -	rdmsrl_safe_on_cpu(cpu, reg, &input);
> -	input &= AMD_ENERGY_MASK;
> -
> -	accum = &data->accums[ch];
> -	if (input >= accum->prev_value)
> -		input += accum->energy_ctr -
> -				accum->prev_value;
> -	else
> -		input += UINT_MAX - accum->prev_value +
> -				accum->energy_ctr;
> -
> -	/* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */
> -	*val = div64_ul(input * 1000000UL, BIT(data->energy_units));
> -
> -	mutex_unlock(&data->lock);
> -}
> -
>  static int amd_energy_read(struct device *dev,
>  			   enum hwmon_sensor_types type,
>  			   u32 attr, int channel, long *val)
>  {
>  	struct amd_energy_data *data = dev_get_drvdata(dev);
> +	struct sensor_accumulator *accum;
>  	u32 reg;
>  	int cpu;
>  
> @@ -162,7 +139,11 @@ static int amd_energy_read(struct device *dev,
>  
>  		reg = ENERGY_CORE_MSR;
>  	}
> -	amd_add_delta(data, channel, cpu, val, reg);
> +
> +	accumulate_delta(data, channel, cpu, reg);
> +	accum = &data->accums[channel];
> +
> +	*val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));

Is it considered safe to read accum->energy_ctr while not holding
data->lock?

>  
>  	return 0;
>  }

If the answer to the question above is "yes" then:

Reviewed-by: Jean Delvare <jdelvare@suse.de>

-- 
Jean Delvare
SUSE L3 Support

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters
  2021-04-09 17:48 ` [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters Guenter Roeck
@ 2021-04-12 12:27   ` Jean Delvare
  2021-04-12 14:25     ` Guenter Roeck
  0 siblings, 1 reply; 8+ messages in thread
From: Jean Delvare @ 2021-04-12 12:27 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Hardware Monitoring, Naveen Krishna Chatradhi, Greg Kroah-Hartman

On Fri,  9 Apr 2021 10:48:52 -0700, Guenter Roeck wrote:
> Commit 60268b0e8258 ("hwmon: (amd_energy) modify the visibility of
> the counters") restricted visibility of AMD energy counters to work
> around a side-channel attack using energy data to determine which
> instructions are executed. The attack is described in 'PLATYPUS:
> Software-based Power Side-Channel Attacks on x86'. It relies on quick
> and accurate energy readings.
> 
> Limiting energy readings to privileged users is annoying. A much better
> solution is to make energy readings unusable for attacks by randomizing
> the time between updates. We can do that by caching energy values for
> a short and randomized period of time.
> 
> Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> ---
> v2: Simplified code by using unified function to accumulate energy data
> 
>  drivers/hwmon/amd_energy.c | 29 +++++++++++++++++++++--------
>  1 file changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
> index 93bad64039f1..1bf0afc2740c 100644
> --- a/drivers/hwmon/amd_energy.c
> +++ b/drivers/hwmon/amd_energy.c
> @@ -18,6 +18,7 @@
>  #include <linux/mutex.h>
>  #include <linux/processor.h>
>  #include <linux/platform_device.h>
> +#include <linux/random.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
>  #include <linux/topology.h>
> @@ -35,6 +36,7 @@
>  struct sensor_accumulator {
>  	u64 energy_ctr;
>  	u64 prev_value;
> +	unsigned long cache_timeout;
>  };
>  
>  struct amd_energy_data {
> @@ -74,17 +76,14 @@ static void get_energy_units(struct amd_energy_data *data)
>  	data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;
>  }
>  

Add a comment stating that this function must be called with accum's
&data->lock held?

> -static void accumulate_delta(struct amd_energy_data *data,
> -			     int channel, int cpu, u32 reg)
> +static void __accumulate_delta(struct sensor_accumulator *accum,
> +			       int cpu, u32 reg)
>  {
> -	struct sensor_accumulator *accum;
>  	u64 input;
>  
> -	mutex_lock(&data->lock);
>  	rdmsrl_safe_on_cpu(cpu, reg, &input);
>  	input &= AMD_ENERGY_MASK;
>  
> -	accum = &data->accums[channel];
>  	if (input >= accum->prev_value)
>  		accum->energy_ctr +=
>  			input - accum->prev_value;
> @@ -93,6 +92,14 @@ static void accumulate_delta(struct amd_energy_data *data,
>  			accum->prev_value + input;
>  
>  	accum->prev_value = input;
> +	accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;

Needs #include <linux/jiffies.h> maybe?

> +}
> +
> +static void accumulate_delta(struct amd_energy_data *data,
> +			     int channel, int cpu, u32 reg)
> +{
> +	mutex_lock(&data->lock);
> +	__accumulate_delta(&data->accums[channel], cpu, reg);
>  	mutex_unlock(&data->lock);
>  }
>  
> @@ -124,6 +131,7 @@ static int amd_energy_read(struct device *dev,
>  {
>  	struct amd_energy_data *data = dev_get_drvdata(dev);
>  	struct sensor_accumulator *accum;
> +	u64 energy;
>  	u32 reg;
>  	int cpu;
>  
> @@ -140,10 +148,15 @@ static int amd_energy_read(struct device *dev,
>  		reg = ENERGY_CORE_MSR;
>  	}
>  
> -	accumulate_delta(data, channel, cpu, reg);
>  	accum = &data->accums[channel];
>  
> -	*val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
> +	mutex_lock(&data->lock);
> +	if (!accum->energy_ctr || time_after(jiffies, accum->cache_timeout))
> +		__accumulate_delta(accum, cpu, reg);
> +	energy = accum->energy_ctr;
> +	mutex_unlock(&data->lock);
> +
> +	*val = div64_ul(energy * 1000000UL, BIT(data->energy_units));
>  
>  	return 0;
>  }
> @@ -152,7 +165,7 @@ static umode_t amd_energy_is_visible(const void *_data,
>  				     enum hwmon_sensor_types type,
>  				     u32 attr, int channel)
>  {
> -	return 0440;
> +	return 0444;
>  }
>  
>  static int energy_accumulator(void *p)

Very nice. This will make the driver useful again :-)

Reviewed-by: Jean Delvare <jdelvare@suse.de>

-- 
Jean Delvare
SUSE L3 Support

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data
  2021-04-12 12:14 ` [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Jean Delvare
@ 2021-04-12 14:17   ` Guenter Roeck
  0 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2021-04-12 14:17 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Hardware Monitoring, Naveen Krishna Chatradhi, Greg Kroah-Hartman

On 4/12/21 5:14 AM, Jean Delvare wrote:
> Hi Guenter,
> 
> On Fri,  9 Apr 2021 10:48:51 -0700, Guenter Roeck wrote:
>> The driver implements two separate functions to read and update
>> energy values. One function is called periodically and updates
>> cached enery information to avoid loss of data, the other reads
>> energy data on demand to report it to userspace. The second
>> function reads current energy data, adds the difference to the
>> data previously obtained by the first function, and then discards
>> the updated data.
>>
>> Simplify the code and always call the first function, then report
>> the energy data obtained by this function to userspace.
> 
> I like the idea.
> 
>> Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>> ---
>> v2: Added patch, simplification
>>
>>  drivers/hwmon/amd_energy.c | 31 ++++++-------------------------
>>  1 file changed, 6 insertions(+), 25 deletions(-)
>>
>> diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
>> index a86cc8d6d93d..93bad64039f1 100644
>> --- a/drivers/hwmon/amd_energy.c
>> +++ b/drivers/hwmon/amd_energy.c
>> @@ -118,35 +118,12 @@ static void read_accumulate(struct amd_energy_data *data)
>>  	data->core_id++;
>>  }
>>  
>> -static void amd_add_delta(struct amd_energy_data *data, int ch,
>> -			  int cpu, long *val, u32 reg)
>> -{
>> -	struct sensor_accumulator *accum;
>> -	u64 input;
>> -
>> -	mutex_lock(&data->lock);
>> -	rdmsrl_safe_on_cpu(cpu, reg, &input);
>> -	input &= AMD_ENERGY_MASK;
>> -
>> -	accum = &data->accums[ch];
>> -	if (input >= accum->prev_value)
>> -		input += accum->energy_ctr -
>> -				accum->prev_value;
>> -	else
>> -		input += UINT_MAX - accum->prev_value +
>> -				accum->energy_ctr;
>> -
>> -	/* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */
>> -	*val = div64_ul(input * 1000000UL, BIT(data->energy_units));
>> -
>> -	mutex_unlock(&data->lock);
>> -}
>> -
>>  static int amd_energy_read(struct device *dev,
>>  			   enum hwmon_sensor_types type,
>>  			   u32 attr, int channel, long *val)
>>  {
>>  	struct amd_energy_data *data = dev_get_drvdata(dev);
>> +	struct sensor_accumulator *accum;
>>  	u32 reg;
>>  	int cpu;
>>  
>> @@ -162,7 +139,11 @@ static int amd_energy_read(struct device *dev,
>>  
>>  		reg = ENERGY_CORE_MSR;
>>  	}
>> -	amd_add_delta(data, channel, cpu, val, reg);
>> +
>> +	accumulate_delta(data, channel, cpu, reg);
>> +	accum = &data->accums[channel];
>> +
>> +	*val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
> 
> Is it considered safe to read accum->energy_ctr while not holding
> data->lock?
> 

You mean because it is a 64-bit value ? Good question; it might not be if compiled
on a 32-bit system. Good news is that I moved reading accum->energy_ctr under the lock
in the next patch, so we should be good.

>>  
>>  	return 0;
>>  }
> 
> If the answer to the question above is "yes" then:
> 
> Reviewed-by: Jean Delvare <jdelvare@suse.de>
> 
Thanks!

Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters
  2021-04-12 12:27   ` Jean Delvare
@ 2021-04-12 14:25     ` Guenter Roeck
  2021-04-19 16:29       ` Chatradhi, Naveen Krishna
  0 siblings, 1 reply; 8+ messages in thread
From: Guenter Roeck @ 2021-04-12 14:25 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Hardware Monitoring, Naveen Krishna Chatradhi, Greg Kroah-Hartman

On 4/12/21 5:27 AM, Jean Delvare wrote:
> On Fri,  9 Apr 2021 10:48:52 -0700, Guenter Roeck wrote:
>> Commit 60268b0e8258 ("hwmon: (amd_energy) modify the visibility of
>> the counters") restricted visibility of AMD energy counters to work
>> around a side-channel attack using energy data to determine which
>> instructions are executed. The attack is described in 'PLATYPUS:
>> Software-based Power Side-Channel Attacks on x86'. It relies on quick
>> and accurate energy readings.
>>
>> Limiting energy readings to privileged users is annoying. A much better
>> solution is to make energy readings unusable for attacks by randomizing
>> the time between updates. We can do that by caching energy values for
>> a short and randomized period of time.
>>
>> Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>> ---
>> v2: Simplified code by using unified function to accumulate energy data
>>
>>  drivers/hwmon/amd_energy.c | 29 +++++++++++++++++++++--------
>>  1 file changed, 21 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
>> index 93bad64039f1..1bf0afc2740c 100644
>> --- a/drivers/hwmon/amd_energy.c
>> +++ b/drivers/hwmon/amd_energy.c
>> @@ -18,6 +18,7 @@
>>  #include <linux/mutex.h>
>>  #include <linux/processor.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/random.h>
>>  #include <linux/sched.h>
>>  #include <linux/slab.h>
>>  #include <linux/topology.h>
>> @@ -35,6 +36,7 @@
>>  struct sensor_accumulator {
>>  	u64 energy_ctr;
>>  	u64 prev_value;
>> +	unsigned long cache_timeout;
>>  };
>>  
>>  struct amd_energy_data {
>> @@ -74,17 +76,14 @@ static void get_energy_units(struct amd_energy_data *data)
>>  	data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;
>>  }
>>  
> 
> Add a comment stating that this function must be called with accum's
> &data->lock held?
> 
>> -static void accumulate_delta(struct amd_energy_data *data,
>> -			     int channel, int cpu, u32 reg)
>> +static void __accumulate_delta(struct sensor_accumulator *accum,
>> +			       int cpu, u32 reg)
>>  {
>> -	struct sensor_accumulator *accum;
>>  	u64 input;
>>  
>> -	mutex_lock(&data->lock);
>>  	rdmsrl_safe_on_cpu(cpu, reg, &input);
>>  	input &= AMD_ENERGY_MASK;
>>  
>> -	accum = &data->accums[channel];
>>  	if (input >= accum->prev_value)
>>  		accum->energy_ctr +=
>>  			input - accum->prev_value;
>> @@ -93,6 +92,14 @@ static void accumulate_delta(struct amd_energy_data *data,
>>  			accum->prev_value + input;
>>  
>>  	accum->prev_value = input;
>> +	accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;
> 
> Needs #include <linux/jiffies.h> maybe?
> 
>> +}
>> +
>> +static void accumulate_delta(struct amd_energy_data *data,
>> +			     int channel, int cpu, u32 reg)
>> +{
>> +	mutex_lock(&data->lock);
>> +	__accumulate_delta(&data->accums[channel], cpu, reg);
>>  	mutex_unlock(&data->lock);
>>  }
>>  
>> @@ -124,6 +131,7 @@ static int amd_energy_read(struct device *dev,
>>  {
>>  	struct amd_energy_data *data = dev_get_drvdata(dev);
>>  	struct sensor_accumulator *accum;
>> +	u64 energy;
>>  	u32 reg;
>>  	int cpu;
>>  
>> @@ -140,10 +148,15 @@ static int amd_energy_read(struct device *dev,
>>  		reg = ENERGY_CORE_MSR;
>>  	}
>>  
>> -	accumulate_delta(data, channel, cpu, reg);
>>  	accum = &data->accums[channel];
>>  
>> -	*val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
>> +	mutex_lock(&data->lock);
>> +	if (!accum->energy_ctr || time_after(jiffies, accum->cache_timeout))
>> +		__accumulate_delta(accum, cpu, reg);
>> +	energy = accum->energy_ctr;
>> +	mutex_unlock(&data->lock);
>> +
>> +	*val = div64_ul(energy * 1000000UL, BIT(data->energy_units));
>>  
>>  	return 0;
>>  }
>> @@ -152,7 +165,7 @@ static umode_t amd_energy_is_visible(const void *_data,
>>  				     enum hwmon_sensor_types type,
>>  				     u32 attr, int channel)
>>  {
>> -	return 0440;
>> +	return 0444;
>>  }
>>  
>>  static int energy_accumulator(void *p)
> 
> Very nice. This will make the driver useful again :-)
> 
> Reviewed-by: Jean Delvare <jdelvare@suse.de>
> 
I made the suggested changes.

Thanks a lot for the review!

Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters
  2021-04-12 14:25     ` Guenter Roeck
@ 2021-04-19 16:29       ` Chatradhi, Naveen Krishna
  2021-04-19 17:41         ` Guenter Roeck
  0 siblings, 1 reply; 8+ messages in thread
From: Chatradhi, Naveen Krishna @ 2021-04-19 16:29 UTC (permalink / raw)
  To: Guenter Roeck, Jean Delvare; +Cc: Hardware Monitoring, Greg Kroah-Hartman

[AMD Official Use Only - Internal Distribution Only]

Hi Guenter,

>>      accum->prev_value = input;
>> +    accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;

I've noticed this change is reviewed and accepted, please note “AMD guidance remains to restrict the RAPL MSR access to privilege users for the CVE-2020-12912. See 2020 tab in https://www.amd.com/en/corporate/product-security#paragraph-313561”

Regards,
Naveenk

-----Original Message-----
From: Guenter Roeck <groeck7@gmail.com> On Behalf Of Guenter Roeck
Sent: Monday, April 12, 2021 7:56 PM
To: Jean Delvare <jdelvare@suse.de>
Cc: Hardware Monitoring <linux-hwmon@vger.kernel.org>; Chatradhi, Naveen Krishna <NaveenKrishna.Chatradhi@amd.com>; Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: Re: [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters

[CAUTION: External Email]

On 4/12/21 5:27 AM, Jean Delvare wrote:
> On Fri,  9 Apr 2021 10:48:52 -0700, Guenter Roeck wrote:
>> Commit 60268b0e8258 ("hwmon: (amd_energy) modify the visibility of 
>> the counters") restricted visibility of AMD energy counters to work 
>> around a side-channel attack using energy data to determine which 
>> instructions are executed. The attack is described in 'PLATYPUS:
>> Software-based Power Side-Channel Attacks on x86'. It relies on quick 
>> and accurate energy readings.
>>
>> Limiting energy readings to privileged users is annoying. A much 
>> better solution is to make energy readings unusable for attacks by 
>> randomizing the time between updates. We can do that by caching 
>> energy values for a short and randomized period of time.
>>
>> Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>> ---
>> v2: Simplified code by using unified function to accumulate energy 
>> data
>>
>>  drivers/hwmon/amd_energy.c | 29 +++++++++++++++++++++--------
>>  1 file changed, 21 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c 
>> index 93bad64039f1..1bf0afc2740c 100644
>> --- a/drivers/hwmon/amd_energy.c
>> +++ b/drivers/hwmon/amd_energy.c
>> @@ -18,6 +18,7 @@
>>  #include <linux/mutex.h>
>>  #include <linux/processor.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/random.h>
>>  #include <linux/sched.h>
>>  #include <linux/slab.h>
>>  #include <linux/topology.h>
>> @@ -35,6 +36,7 @@
>>  struct sensor_accumulator {
>>      u64 energy_ctr;
>>      u64 prev_value;
>> +    unsigned long cache_timeout;
>>  };
>>
>>  struct amd_energy_data {
>> @@ -74,17 +76,14 @@ static void get_energy_units(struct amd_energy_data *data)
>>      data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;  
>> }
>>
>
> Add a comment stating that this function must be called with accum's 
> &data->lock held?
>
>> -static void accumulate_delta(struct amd_energy_data *data,
>> -                         int channel, int cpu, u32 reg)
>> +static void __accumulate_delta(struct sensor_accumulator *accum,
>> +                           int cpu, u32 reg)
>>  {
>> -    struct sensor_accumulator *accum;
>>      u64 input;
>>
>> -    mutex_lock(&data->lock);
>>      rdmsrl_safe_on_cpu(cpu, reg, &input);
>>      input &= AMD_ENERGY_MASK;
>>
>> -    accum = &data->accums[channel];
>>      if (input >= accum->prev_value)
>>              accum->energy_ctr +=
>>                      input - accum->prev_value; @@ -93,6 +92,14 @@ 
>> static void accumulate_delta(struct amd_energy_data *data,
>>                      accum->prev_value + input;
>>
>>      accum->prev_value = input;
>> +    accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;
>
> Needs #include <linux/jiffies.h> maybe?
>
>> +}
>> +
>> +static void accumulate_delta(struct amd_energy_data *data,
>> +                         int channel, int cpu, u32 reg) {
>> +    mutex_lock(&data->lock);
>> +    __accumulate_delta(&data->accums[channel], cpu, reg);
>>      mutex_unlock(&data->lock);
>>  }
>>
>> @@ -124,6 +131,7 @@ static int amd_energy_read(struct device *dev,  {
>>      struct amd_energy_data *data = dev_get_drvdata(dev);
>>      struct sensor_accumulator *accum;
>> +    u64 energy;
>>      u32 reg;
>>      int cpu;
>>
>> @@ -140,10 +148,15 @@ static int amd_energy_read(struct device *dev,
>>              reg = ENERGY_CORE_MSR;
>>      }
>>
>> -    accumulate_delta(data, channel, cpu, reg);
>>      accum = &data->accums[channel];
>>
>> -    *val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
>> +    mutex_lock(&data->lock);
>> +    if (!accum->energy_ctr || time_after(jiffies, accum->cache_timeout))
>> +            __accumulate_delta(accum, cpu, reg);
>> +    energy = accum->energy_ctr;
>> +    mutex_unlock(&data->lock);
>> +
>> +    *val = div64_ul(energy * 1000000UL, BIT(data->energy_units));
>>
>>      return 0;
>>  }
>> @@ -152,7 +165,7 @@ static umode_t amd_energy_is_visible(const void *_data,
>>                                   enum hwmon_sensor_types type,
>>                                   u32 attr, int channel)  {
>> -    return 0440;
>> +    return 0444;
>>  }
>>
>>  static int energy_accumulator(void *p)
>
> Very nice. This will make the driver useful again :-)
>
> Reviewed-by: Jean Delvare <jdelvare@suse.de>
>
I made the suggested changes.

Thanks a lot for the review!

Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters
  2021-04-19 16:29       ` Chatradhi, Naveen Krishna
@ 2021-04-19 17:41         ` Guenter Roeck
  0 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2021-04-19 17:41 UTC (permalink / raw)
  To: Chatradhi, Naveen Krishna
  Cc: Jean Delvare, Hardware Monitoring, Greg Kroah-Hartman

On Mon, Apr 19, 2021 at 04:29:59PM +0000, Chatradhi, Naveen Krishna wrote:
> [AMD Official Use Only - Internal Distribution Only]
> 
> Hi Guenter,
> 
> >>      accum->prev_value = input;
> >> +    accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;
> 
> I've noticed this change is reviewed and accepted, please note “AMD guidance remains to restrict the RAPL MSR access to privilege users for the CVE-2020-12912. See 2020 tab in https://www.amd.com/en/corporate/product-security#paragraph-313561”
> 

This has been on the list for a while, so your feedback is a tiny
bit late.

Please feel free to send a NACK to the patch. If my suggested solution
is not acceptable, I'll remove the driver entirely and add a note
to the sysfs ABI stating that attributes MUST be world readable
for a driver to be acceptable. After all, this patch forces users
of the hwmon ABI to run previously restricted applications as
super-user (or to revert the patch introducing the restrictions
in their private builds), which completely defeats the purpose
of the patch and opens up additional unnecessary attack surface. 

Thanks,
Guenter

> Regards,
> Naveenk
> 
> -----Original Message-----
> From: Guenter Roeck <groeck7@gmail.com> On Behalf Of Guenter Roeck
> Sent: Monday, April 12, 2021 7:56 PM
> To: Jean Delvare <jdelvare@suse.de>
> Cc: Hardware Monitoring <linux-hwmon@vger.kernel.org>; Chatradhi, Naveen Krishna <NaveenKrishna.Chatradhi@amd.com>; Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Subject: Re: [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters
> 
> [CAUTION: External Email]
> 
> On 4/12/21 5:27 AM, Jean Delvare wrote:
> > On Fri,  9 Apr 2021 10:48:52 -0700, Guenter Roeck wrote:
> >> Commit 60268b0e8258 ("hwmon: (amd_energy) modify the visibility of 
> >> the counters") restricted visibility of AMD energy counters to work 
> >> around a side-channel attack using energy data to determine which 
> >> instructions are executed. The attack is described in 'PLATYPUS:
> >> Software-based Power Side-Channel Attacks on x86'. It relies on quick 
> >> and accurate energy readings.
> >>
> >> Limiting energy readings to privileged users is annoying. A much 
> >> better solution is to make energy readings unusable for attacks by 
> >> randomizing the time between updates. We can do that by caching 
> >> energy values for a short and randomized period of time.
> >>
> >> Cc: Naveen Krishna Chatradhi <nchatrad@amd.com>
> >> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> >> ---
> >> v2: Simplified code by using unified function to accumulate energy 
> >> data
> >>
> >>  drivers/hwmon/amd_energy.c | 29 +++++++++++++++++++++--------
> >>  1 file changed, 21 insertions(+), 8 deletions(-)
> >>
> >> diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c 
> >> index 93bad64039f1..1bf0afc2740c 100644
> >> --- a/drivers/hwmon/amd_energy.c
> >> +++ b/drivers/hwmon/amd_energy.c
> >> @@ -18,6 +18,7 @@
> >>  #include <linux/mutex.h>
> >>  #include <linux/processor.h>
> >>  #include <linux/platform_device.h>
> >> +#include <linux/random.h>
> >>  #include <linux/sched.h>
> >>  #include <linux/slab.h>
> >>  #include <linux/topology.h>
> >> @@ -35,6 +36,7 @@
> >>  struct sensor_accumulator {
> >>      u64 energy_ctr;
> >>      u64 prev_value;
> >> +    unsigned long cache_timeout;
> >>  };
> >>
> >>  struct amd_energy_data {
> >> @@ -74,17 +76,14 @@ static void get_energy_units(struct amd_energy_data *data)
> >>      data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;  
> >> }
> >>
> >
> > Add a comment stating that this function must be called with accum's 
> > &data->lock held?
> >
> >> -static void accumulate_delta(struct amd_energy_data *data,
> >> -                         int channel, int cpu, u32 reg)
> >> +static void __accumulate_delta(struct sensor_accumulator *accum,
> >> +                           int cpu, u32 reg)
> >>  {
> >> -    struct sensor_accumulator *accum;
> >>      u64 input;
> >>
> >> -    mutex_lock(&data->lock);
> >>      rdmsrl_safe_on_cpu(cpu, reg, &input);
> >>      input &= AMD_ENERGY_MASK;
> >>
> >> -    accum = &data->accums[channel];
> >>      if (input >= accum->prev_value)
> >>              accum->energy_ctr +=
> >>                      input - accum->prev_value; @@ -93,6 +92,14 @@ 
> >> static void accumulate_delta(struct amd_energy_data *data,
> >>                      accum->prev_value + input;
> >>
> >>      accum->prev_value = input;
> >> +    accum->cache_timeout = jiffies + HZ + get_random_int() % HZ;
> >
> > Needs #include <linux/jiffies.h> maybe?
> >
> >> +}
> >> +
> >> +static void accumulate_delta(struct amd_energy_data *data,
> >> +                         int channel, int cpu, u32 reg) {
> >> +    mutex_lock(&data->lock);
> >> +    __accumulate_delta(&data->accums[channel], cpu, reg);
> >>      mutex_unlock(&data->lock);
> >>  }
> >>
> >> @@ -124,6 +131,7 @@ static int amd_energy_read(struct device *dev,  {
> >>      struct amd_energy_data *data = dev_get_drvdata(dev);
> >>      struct sensor_accumulator *accum;
> >> +    u64 energy;
> >>      u32 reg;
> >>      int cpu;
> >>
> >> @@ -140,10 +148,15 @@ static int amd_energy_read(struct device *dev,
> >>              reg = ENERGY_CORE_MSR;
> >>      }
> >>
> >> -    accumulate_delta(data, channel, cpu, reg);
> >>      accum = &data->accums[channel];
> >>
> >> -    *val = div64_ul(accum->energy_ctr * 1000000UL, BIT(data->energy_units));
> >> +    mutex_lock(&data->lock);
> >> +    if (!accum->energy_ctr || time_after(jiffies, accum->cache_timeout))
> >> +            __accumulate_delta(accum, cpu, reg);
> >> +    energy = accum->energy_ctr;
> >> +    mutex_unlock(&data->lock);
> >> +
> >> +    *val = div64_ul(energy * 1000000UL, BIT(data->energy_units));
> >>
> >>      return 0;
> >>  }
> >> @@ -152,7 +165,7 @@ static umode_t amd_energy_is_visible(const void *_data,
> >>                                   enum hwmon_sensor_types type,
> >>                                   u32 attr, int channel)  {
> >> -    return 0440;
> >> +    return 0444;
> >>  }
> >>
> >>  static int energy_accumulator(void *p)
> >
> > Very nice. This will make the driver useful again :-)
> >
> > Reviewed-by: Jean Delvare <jdelvare@suse.de>
> >
> I made the suggested changes.
> 
> Thanks a lot for the review!
> 
> Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-04-19 17:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-09 17:48 [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Guenter Roeck
2021-04-09 17:48 ` [PATCH v2 2/2] hwmon: (amd_energy) Restore visibility of energy counters Guenter Roeck
2021-04-12 12:27   ` Jean Delvare
2021-04-12 14:25     ` Guenter Roeck
2021-04-19 16:29       ` Chatradhi, Naveen Krishna
2021-04-19 17:41         ` Guenter Roeck
2021-04-12 12:14 ` [PATCH v2 1/2] hwmon: (amd_energy) Use unified function to read energy data Jean Delvare
2021-04-12 14:17   ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).