diff mbox series

[9/9] media: pci: mgb4: fix potential spectre vulnerability

Message ID c83b7fffe1e087568f64aba786797d258279948e.1696586632.git.hverkuil-cisco@xs4all.nl (mailing list archive)
State New, archived
Headers show
Series media: fix smatch warnings | expand

Commit Message

Hans Verkuil Oct. 6, 2023, 10:08 a.m. UTC
Fix smatch warnings:

drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap)
drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half.  'loopin_new'

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
CC: Martin Tuma <martin.tuma@digiteqautomotive.com>
---
 drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

Comments

Martin Tůma Oct. 10, 2023, 10:31 a.m. UTC | #1
On 06. 10. 23 12:08, Hans Verkuil wrote:
> Fix smatch warnings:
> 
> drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap)
> drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half.  'loopin_new'
> 
> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> CC: Martin Tuma <martin.tuma@digiteqautomotive.com>
> ---
>   drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> index 23a9aabf3915..9f6e81c57726 100644
> --- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> @@ -8,6 +8,7 @@
>    */
>   
>   #include <linux/device.h>
> +#include <linux/nospec.h>
>   #include "mgb4_core.h"
>   #include "mgb4_i2c.h"
>   #include "mgb4_vout.h"
> @@ -114,8 +115,10 @@ static ssize_t video_source_store(struct device *dev,
>   
>   	if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES)
>   		loopin_old = mgbdev->vin[(config & 0xc) >> 2];
> -	if (val < MGB4_VIN_DEVICES)
> +	if (val < MGB4_VIN_DEVICES) {
> +		val = array_index_nospec(val, MGB4_VIN_DEVICES);
>   		loopin_new = mgbdev->vin[val];
> +	}
>   	if (loopin_old && loopin_cnt(loopin_old) == 1)
>   		mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config,
>   			      0x2, 0x0);

Hi,
I had investigated the warning when it appeared here on the mailing 
list, but IMHO it is a false-positive, so I didn't react to it. 
MGB4_VIN_DEVICES in the condition is not a check for array bounds but a 
check whether the input source (val) is one of the inputs. Valid "val" 
values are <0,3> and only if the value is <0,1> it is used as an array 
index for the input devices (vin) array. So this is IMHO a different 
situation than desribed in the speculation document 
(https://www.kernel.org/doc/html/latest/staging/speculation.html). But I 
may be wrong and array_index_nospec() is still required here.

If the goal was just to silence smatch, than I'm ok with that, It 
shouldn't harm any performance here. Except that it will look like there 
is a possible spectre issue in the code where it in fact isn't, it 
should not change anything.

M.
Pawan Gupta Oct. 11, 2023, 12:35 a.m. UTC | #2
On Tue, Oct 10, 2023 at 12:31:07PM +0200, Martin Tůma wrote:
> On 06. 10. 23 12:08, Hans Verkuil wrote:
> > Fix smatch warnings:
> > 
> > drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap)
> > drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half.  'loopin_new'
> > 
> > Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> > CC: Martin Tuma <martin.tuma@digiteqautomotive.com>
> > ---
> >   drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++-
> >   1 file changed, 4 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> > index 23a9aabf3915..9f6e81c57726 100644
> > --- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> > +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> > @@ -8,6 +8,7 @@
> >    */
> >   #include <linux/device.h>
> > +#include <linux/nospec.h>
> >   #include "mgb4_core.h"
> >   #include "mgb4_i2c.h"
> >   #include "mgb4_vout.h"
> > @@ -114,8 +115,10 @@ static ssize_t video_source_store(struct device *dev,
> >   	if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES)
> >   		loopin_old = mgbdev->vin[(config & 0xc) >> 2];
> > -	if (val < MGB4_VIN_DEVICES)
> > +	if (val < MGB4_VIN_DEVICES) {
> > +		val = array_index_nospec(val, MGB4_VIN_DEVICES);
> >   		loopin_new = mgbdev->vin[val];
> > +	}
> >   	if (loopin_old && loopin_cnt(loopin_old) == 1)
> >   		mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config,
> >   			      0x2, 0x0);
> 
> Hi,
> I had investigated the warning when it appeared here on the mailing list,
> but IMHO it is a false-positive, so I didn't react to it. MGB4_VIN_DEVICES
> in the condition is not a check for array bounds but a check whether the
> input source (val) is one of the inputs. Valid "val" values are <0,3> and
> only if the value is <0,1> it is used as an array index for the input
> devices (vin) array.

I think when there are 2 branch mispredicts this is a valid problem.
Below both branches can be trained with a val < 2. Then for a val > 3,
both branches can mispredict:

video_source_store(buf)
{
...
	ret = kstrtoul(buf, 10, &val);
	if (ret)
		return ret;
	if (val > 3)		     <------------- predicted as not taken
		return -EINVAL;
	...

	if (val < MGB4_VIN_DEVICES)  <------------- predicted as taken
 		loopin_new = mgbdev->vin[val];

The fix LGTM, although it can also possibly be fixed by masking the
index after the first mispredicted branch, like:

	ret = kstrtoul(buf, 10, &val);
	if (ret)
		return ret;

+	val = array_index_nospec(val, 4);

provided, mgbdev->vin[2] and mgbdev->vin[3] can't load a secret.
Hans Verkuil Oct. 11, 2023, 4:36 p.m. UTC | #3
Hi Martin,

On 11/10/2023 02:35, Pawan Gupta wrote:
> On Tue, Oct 10, 2023 at 12:31:07PM +0200, Martin Tůma wrote:
>> On 06. 10. 23 12:08, Hans Verkuil wrote:
>>> Fix smatch warnings:
>>>
>>> drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap)
>>> drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half.  'loopin_new'>>>
>>> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>> CC: Martin Tuma <martin.tuma@digiteqautomotive.com>
>>> ---
>>>   drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++-
>>>   1 file changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
>>> index 23a9aabf3915..9f6e81c57726 100644
>>> --- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c
>>> +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
>>> @@ -8,6 +8,7 @@
>>>    */
>>>   #include <linux/device.h>
>>> +#include <linux/nospec.h>
>>>   #include "mgb4_core.h"
>>>   #include "mgb4_i2c.h"
>>>   #include "mgb4_vout.h"
>>> @@ -114,8 +115,10 @@ static ssize_t video_source_store(struct device *dev,
>>>   	if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES)
>>>   		loopin_old = mgbdev->vin[(config & 0xc) >> 2];
>>> -	if (val < MGB4_VIN_DEVICES)
>>> +	if (val < MGB4_VIN_DEVICES) {
>>> +		val = array_index_nospec(val, MGB4_VIN_DEVICES);
>>>   		loopin_new = mgbdev->vin[val];
>>> +	}
>>>   	if (loopin_old && loopin_cnt(loopin_old) == 1)
>>>   		mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config,
>>>   			      0x2, 0x0);
>>
>> Hi,
>> I had investigated the warning when it appeared here on the mailing list,
>> but IMHO it is a false-positive, so I didn't react to it. MGB4_VIN_DEVICES
>> in the condition is not a check for array bounds but a check whether the
>> input source (val) is one of the inputs. Valid "val" values are <0,3> and
>> only if the value is <0,1> it is used as an array index for the input
>> devices (vin) array.
> 
> I think when there are 2 branch mispredicts this is a valid problem.
> Below both branches can be trained with a val < 2. Then for a val > 3,
> both branches can mispredict:
> 
> video_source_store(buf)
> {
> ...
> 	ret = kstrtoul(buf, 10, &val);
> 	if (ret)
> 		return ret;
> 	if (val > 3)		     <------------- predicted as not taken
> 		return -EINVAL;
> 	...
> 
> 	if (val < MGB4_VIN_DEVICES)  <------------- predicted as taken
>  		loopin_new = mgbdev->vin[val];
> 
> The fix LGTM, although it can also possibly be fixed by masking the
> index after the first mispredicted branch, like:
> 
> 	ret = kstrtoul(buf, 10, &val);
> 	if (ret)
> 		return ret;
> 
> +	val = array_index_nospec(val, 4);
> 
> provided, mgbdev->vin[2] and mgbdev->vin[3] can't load a secret.

Based on that input, and also because I want to shut up that warnings :-),
is it OK to merge? Can you proved and Acked-by or Reviewed-by?

Thanks!

	Hans
Martin Tůma Oct. 12, 2023, 9:08 a.m. UTC | #4
On 06. 10. 23 12:08, Hans Verkuil wrote:
> Fix smatch warnings:
> 
> drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap)
> drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half.  'loopin_new'
> 
> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> CC: Martin Tuma <martin.tuma@digiteqautomotive.com>
> ---
>   drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> index 23a9aabf3915..9f6e81c57726 100644
> --- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
> @@ -8,6 +8,7 @@
>    */
>   
>   #include <linux/device.h>
> +#include <linux/nospec.h>
>   #include "mgb4_core.h"
>   #include "mgb4_i2c.h"
>   #include "mgb4_vout.h"
> @@ -114,8 +115,10 @@ static ssize_t video_source_store(struct device *dev,
>   
>   	if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES)
>   		loopin_old = mgbdev->vin[(config & 0xc) >> 2];
> -	if (val < MGB4_VIN_DEVICES)
> +	if (val < MGB4_VIN_DEVICES) {
> +		val = array_index_nospec(val, MGB4_VIN_DEVICES);
>   		loopin_new = mgbdev->vin[val];
> +	}
>   	if (loopin_old && loopin_cnt(loopin_old) == 1)
>   		mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config,
>   			      0x2, 0x0);

Reviewed-by: Martin Tůma <martin.tuma@digiteqautomotive.com>
Martin Tůma Oct. 12, 2023, 9:09 a.m. UTC | #5
On 11. 10. 23 2:35, Pawan Gupta wrote:
> On Tue, Oct 10, 2023 at 12:31:07PM +0200, Martin Tůma wrote:
>> On 06. 10. 23 12:08, Hans Verkuil wrote:
>>> Fix smatch warnings:
>>>
>>> drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap)
>>> drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half.  'loopin_new'
>>>
>>> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>> CC: Martin Tuma <martin.tuma@digiteqautomotive.com>
>>> ---
>>>    drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++-
>>>    1 file changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
>>> index 23a9aabf3915..9f6e81c57726 100644
>>> --- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c
>>> +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
>>> @@ -8,6 +8,7 @@
>>>     */
>>>    #include <linux/device.h>
>>> +#include <linux/nospec.h>
>>>    #include "mgb4_core.h"
>>>    #include "mgb4_i2c.h"
>>>    #include "mgb4_vout.h"
>>> @@ -114,8 +115,10 @@ static ssize_t video_source_store(struct device *dev,
>>>    	if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES)
>>>    		loopin_old = mgbdev->vin[(config & 0xc) >> 2];
>>> -	if (val < MGB4_VIN_DEVICES)
>>> +	if (val < MGB4_VIN_DEVICES) {
>>> +		val = array_index_nospec(val, MGB4_VIN_DEVICES);
>>>    		loopin_new = mgbdev->vin[val];
>>> +	}
>>>    	if (loopin_old && loopin_cnt(loopin_old) == 1)
>>>    		mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config,
>>>    			      0x2, 0x0);
>>
>> Hi,
>> I had investigated the warning when it appeared here on the mailing list,
>> but IMHO it is a false-positive, so I didn't react to it. MGB4_VIN_DEVICES
>> in the condition is not a check for array bounds but a check whether the
>> input source (val) is one of the inputs. Valid "val" values are <0,3> and
>> only if the value is <0,1> it is used as an array index for the input
>> devices (vin) array.
> 
> I think when there are 2 branch mispredicts this is a valid problem.
> Below both branches can be trained with a val < 2. Then for a val > 3,
> both branches can mispredict:
> 
> video_source_store(buf)
> {
> ...
> 	ret = kstrtoul(buf, 10, &val);
> 	if (ret)
> 		return ret;
> 	if (val > 3)		     <------------- predicted as not taken
> 		return -EINVAL;
> 	...
> 
> 	if (val < MGB4_VIN_DEVICES)  <------------- predicted as taken
>   		loopin_new = mgbdev->vin[val];
> 
> The fix LGTM, although it can also possibly be fixed by masking the
> index after the first mispredicted branch, like:
> 
> 	ret = kstrtoul(buf, 10, &val);
> 	if (ret)
> 		return ret;
> 
> +	val = array_index_nospec(val, 4);
> 

Ok, thanks for the clarification.

> provided, mgbdev->vin[2] and mgbdev->vin[3] can't load a secret.

There is nothing secret there.

M.
diff mbox series

Patch

diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
index 23a9aabf3915..9f6e81c57726 100644
--- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c
+++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c
@@ -8,6 +8,7 @@ 
  */
 
 #include <linux/device.h>
+#include <linux/nospec.h>
 #include "mgb4_core.h"
 #include "mgb4_i2c.h"
 #include "mgb4_vout.h"
@@ -114,8 +115,10 @@  static ssize_t video_source_store(struct device *dev,
 
 	if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES)
 		loopin_old = mgbdev->vin[(config & 0xc) >> 2];
-	if (val < MGB4_VIN_DEVICES)
+	if (val < MGB4_VIN_DEVICES) {
+		val = array_index_nospec(val, MGB4_VIN_DEVICES);
 		loopin_new = mgbdev->vin[val];
+	}
 	if (loopin_old && loopin_cnt(loopin_old) == 1)
 		mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config,
 			      0x2, 0x0);