@@ -156,6 +156,7 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
void *arg, bool check_size)
{
struct pci_vpd *vpd = &dev->vpd;
+ struct pci_driver *drv;
unsigned int max_len;
int ret = 0;
loff_t end = pos + count;
@@ -167,6 +168,12 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
if (pos < 0)
return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN)) {
+ drv = to_pci_driver(dev->dev.driver);
+ if (!drv || !drv->downgrade_vpd_read)
+ return -EPERM;
+ }
+
max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
if (pos >= max_len)
@@ -317,7 +324,7 @@ static ssize_t vpd_write(struct file *filp, struct kobject *kobj,
return ret;
}
-static BIN_ATTR(vpd, 0600, vpd_read, vpd_write, 0);
+static BIN_ATTR_RW(vpd, 0);
static struct bin_attribute *vpd_attrs[] = {
&bin_attr_vpd,
@@ -943,6 +943,10 @@ struct module;
* how to manage the DMA themselves and set this flag so that
* the IOMMU layer will allow them to setup and manage their
* own I/O address space.
+ * @downgrade_vpd_read: Device doesn't require root permissions from the users
+ * to read VPD information. The driver doesn't expose any sensitive
+ * information through that interface and safe to be accessed by
+ * unprivileged users.
*/
struct pci_driver {
const char *name;
@@ -960,7 +964,8 @@ struct pci_driver {
const struct attribute_group **dev_groups;
struct device_driver driver;
struct pci_dynids dynids;
- bool driver_managed_dma;
+ bool driver_managed_dma : 1;
+ bool downgrade_vpd_read : 1;
};
#define to_pci_driver(__drv) \