commit 9b08de74613b95152094721aa5b55e790d704aec Author: Jason S. McMullan Date: Thu Apr 30 19:15:30 2015 -0400 udev/net_id: Only read the first 64 bytes of PCI config space The original code used fread(), which on some libc implementions (ie glibc 2.17) would pre-read a full 4K (PAGE_SIZE) of the PCI config space, when only 64 bytes were requested. I have recently come across PCIe hardware which responds with Completion Timeouts when accesses above 256 bytes are attempted. This can cause server systems with GHES/AEPI support to cause and immediate kernel panic due to the failed PCI transaction. This change replaces the buffered fread() with an explict unbuffered read() of 64 bytes, which corrects this issue by only reading the guaranteed first 64 bytes of PCIe config space. Signed-off-by: Jason S. McMullan diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 9ae8f08..6ca9723 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -88,6 +88,7 @@ #include #include #include +#include #include #include #include @@ -144,23 +145,23 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { /* read the 256 bytes PCI configuration space to check the multi-function bit */ static bool is_pci_multifunction(struct udev_device *dev) { char filename[256]; - FILE *f = NULL; + int fd = -1; char config[64]; bool multi = false; snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev)); - f = fopen(filename, "re"); - if (!f) + fd = open(filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) goto out; - if (fread(&config, sizeof(config), 1, f) != 1) + if (read(fd, &config, sizeof(config)) != sizeof(config)) goto out; /* bit 0-6 header type, bit 7 multi/single function device */ if ((config[PCI_HEADER_TYPE] & 0x80) != 0) multi = true; out: - if(f) - fclose(f); + if(fd >= 0) + close(fd); return multi; }