The "partition" member of the struct switchtec_ioctl_pff_port can be
indirectly controlled from user-space through an IOCTL that the device
driver provides enabling conversion between a PCI Function Framework (PFF)
number and Switchtec logical port ID and partition number, thus allowing
for command-line tooling [1] interact with the device from user-space.
This can lead to potential exploitation of the Spectre variant 1 [2]
vulnerability since the value of the partition is then used directly as an
index to mmio_part_cfg_all[] of the struct switchtec_dev to retrieve
configuration from Switchtec for a specific partition number.
Fix this by sanitizing the value coming from user-space through the
available IOCTL before it's then used as an index to mmio_part_cfg_all[].
This issue was detected with the help of Smatch:
drivers/pci/switch/switchtec.c:1118 ioctl_port_to_pff() warn:
potential spectre issue 'stdev->mmio_part_cfg_all' [r] (local cap)
Notice that given that speculation windows are large, the policy is to kill
the speculation on the first load and not worry if it can be completed with
a dependent load/store [3].
Related commit
46feb6b495f7 ("switchtec: Fix Spectre v1 vulnerability").
[1] https://github.com/Microsemi/switchtec-user/blob/master/lib/platform/linux.c
[2] https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/spectre.html
[3] https://lore.kernel.org/lkml/CAPcyv4gLKYiCtXsKFX2FY+rW93aRtQt9zB8hU1hMsj770m8gxQ@mail.gmail.com/
Link: https://lore.kernel.org/r/20210220062837.1683159-1-kw@linux.com
Signed-off-by: Krzysztof Wilczyński <kw@linux.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
if (copy_from_user(&p, up, sizeof(p)))
return -EFAULT;
- if (p.partition == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX)
+ if (p.partition == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX) {
pcfg = stdev->mmio_part_cfg;
- else if (p.partition < stdev->partition_count)
+ } else if (p.partition < stdev->partition_count) {
+ p.partition = array_index_nospec(p.partition,
+ stdev->partition_count);
pcfg = &stdev->mmio_part_cfg_all[p.partition];
- else
+ } else {
return -EINVAL;
+ }
switch (p.port) {
case 0: