[bug report] vfio/pci: Add OpRegion 2.0+ Extended VBT support.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Colin Xu,

The patch 49ba1a2976c8: "vfio/pci: Add OpRegion 2.0+ Extended VBT
support." from Oct 12, 2021, leads to the following Smatch static
checker warning:

	drivers/vfio/pci/vfio_pci_igd.c:101 vfio_pci_igd_rw()
	warn: potential pointer math issue ('&version' is a 16 bit pointer)

	drivers/vfio/pci/vfio_pci_igd.c:124 vfio_pci_igd_rw()
	warn: potential pointer math issue ('&rvda' is a 64 bit pointer)

drivers/vfio/pci/vfio_pci_igd.c
    64 static ssize_t vfio_pci_igd_rw(struct vfio_pci_core_device *vdev,
    65                                char __user *buf, size_t count, loff_t *ppos,
    66                                bool iswrite)
    67 {
    68         unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS;
    69         struct igd_opregion_vbt *opregionvbt = vdev->region[i].data;
    70         loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK, off = 0;
    71         size_t remaining;
    72 
    73         if (pos >= vdev->region[i].size || iswrite)
    74                 return -EINVAL;
    75 
    76         count = min_t(size_t, count, vdev->region[i].size - pos);
    77         remaining = count;
    78 
    79         /* Copy until OpRegion version */
    80         if (remaining && pos < OPREGION_VERSION) {
    81                 size_t bytes = min_t(size_t, remaining, OPREGION_VERSION - pos);
    82 
    83                 if (igd_opregion_shift_copy(buf, &off,
    84                                             opregionvbt->opregion + pos, &pos,
    85                                             &remaining, bytes))
    86                         return -EFAULT;
    87         }
    88 
    89         /* Copy patched (if necessary) OpRegion version */
    90         if (remaining && pos < OPREGION_VERSION + sizeof(__le16)) {
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The sizeof() means we know "pos" is a number of bytes.

    91                 size_t bytes = min_t(size_t, remaining,
    92                                      OPREGION_VERSION + sizeof(__le16) - pos);
    93                 __le16 version = *(__le16 *)(opregionvbt->opregion +
                       ^^^^^^^^^^^^^^
Version is a stack variable.  I think version was supposed to be a
pointer.
			u8 *v = opregionvbt->opregion + OPREGION_VERSION;
			__le16 version = *(__le16 *)v;

    94                                              OPREGION_VERSION);
    95 
    96                 /* Patch to 2.1 if OpRegion 2.0 has extended VBT */
    97                 if (le16_to_cpu(version) == 0x0200 && opregionvbt->vbt_ex)
    98                         version = cpu_to_le16(0x0201);
    99 
    100                 if (igd_opregion_shift_copy(buf, &off,
--> 101                                             &version + (pos - OPREGION_VERSION),
                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The math doesn't work because we're changing from byte units to
sizeof(version) units, but the more important question is why are we
copying stack data anyway?  :P

			if (igd_opregion_shift_copy(buf, &off,
						    p + (pos - OPREGION_VERSION),
						    &pos, &remaining, bytes))


    102                                             &pos, &remaining, bytes))
    103                         return -EFAULT;
    104         }
    105 
    106         /* Copy until RVDA */
    107         if (remaining && pos < OPREGION_RVDA) {
    108                 size_t bytes = min_t(size_t, remaining, OPREGION_RVDA - pos);
    109 
    110                 if (igd_opregion_shift_copy(buf, &off,
    111                                             opregionvbt->opregion + pos, &pos,
    112                                             &remaining, bytes))
    113                         return -EFAULT;
    114         }
    115 
    116         /* Copy modified (if necessary) RVDA */
    117         if (remaining && pos < OPREGION_RVDA + sizeof(__le64)) {
    118                 size_t bytes = min_t(size_t, remaining,
    119                                      OPREGION_RVDA + sizeof(__le64) - pos);
    120                 __le64 rvda = cpu_to_le64(opregionvbt->vbt_ex ?
    121                                           OPREGION_SIZE : 0);
    122 
    123                 if (igd_opregion_shift_copy(buf, &off,
    124                                             &rvda + (pos - OPREGION_RVDA),


Same thing here.  The pointer math is wrong and copying stack data is
wrong too.

    125                                             &pos, &remaining, bytes))
    126                         return -EFAULT;
    127         }
    128 
    129         /* Copy the rest of OpRegion */
    130         if (remaining && pos < OPREGION_SIZE) {
    131                 size_t bytes = min_t(size_t, remaining, OPREGION_SIZE - pos);
    132 
    133                 if (igd_opregion_shift_copy(buf, &off,
    134                                             opregionvbt->opregion + pos, &pos,
    135                                             &remaining, bytes))
    136                         return -EFAULT;
    137         }
    138 
    139         /* Copy extended VBT if exists */
    140         if (remaining &&
    141             copy_to_user(buf + off, opregionvbt->vbt_ex + (pos - OPREGION_SIZE),
    142                          remaining))
    143                 return -EFAULT;
    144 
    145         *ppos += count;
    146 
    147         return count;
    148 }

regards,
dan carpenter



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux