1ff636
From 210ec6353d3cab2029e1eb160671fea918c97814 Mon Sep 17 00:00:00 2001
1ff636
From: "Jason S. McMullan" <jason.mcmullan@gmail.com>
1ff636
Date: Fri, 22 May 2015 20:30:01 +0200
1ff636
Subject: [PATCH] udev/net_id: Only read the first 64 bytes of PCI config space
1ff636
1ff636
The original code used fread(), which on some libc implementions
1ff636
(ie glibc 2.17) would pre-read a full 4K (PAGE_SIZE) of the
1ff636
PCI config space, when only 64 bytes were requested.
1ff636
1ff636
I have recently come across PCIe hardware which responds with
1ff636
Completion Timeouts when accesses above 256 bytes are attempted.
1ff636
1ff636
This can cause server systems with GHES/AEPI support to cause
1ff636
and immediate kernel panic due to the failed PCI transaction.
1ff636
1ff636
This change replaces the buffered fread() with an explict
1ff636
unbuffered read() of 64 bytes, which corrects this issue by
1ff636
only reading the guaranteed first 64 bytes of PCIe config space.
1ff636
1ff636
(cherry picked from commit 0454229c100a2113ba82df55703436d6cb2c492b)
1ff636
1ff636
Cherry-picked from: 0454229
1ff636
Resolves: #1222517
1ff636
---
1ff636
 src/udev/udev-builtin-net_id.c | 9 +++++----
1ff636
 1 file changed, 5 insertions(+), 4 deletions(-)
1ff636
1ff636
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
c62b8e
index 66474f7728..dd2886caf2 100644
1ff636
--- a/src/udev/udev-builtin-net_id.c
1ff636
+++ b/src/udev/udev-builtin-net_id.c
1ff636
@@ -91,6 +91,7 @@
1ff636
 #include <stdlib.h>
1ff636
 #include <stdarg.h>
1ff636
 #include <unistd.h>
1ff636
+#include <fcntl.h>
1ff636
 #include <string.h>
1ff636
 #include <errno.h>
1ff636
 #include <net/if.h>
1ff636
@@ -166,15 +167,15 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
1ff636
 
1ff636
 /* read the 256 bytes PCI configuration space to check the multi-function bit */
1ff636
 static bool is_pci_multifunction(struct udev_device *dev) {
1ff636
-        _cleanup_fclose_ FILE *f = NULL;
1ff636
+        _cleanup_close_ int fd = -1;
1ff636
         const char *filename;
1ff636
         uint8_t config[64];
1ff636
 
1ff636
         filename = strjoina(udev_device_get_syspath(dev), "/config");
1ff636
-        f = fopen(filename, "re");
1ff636
-        if (!f)
1ff636
+        fd = open(filename, O_RDONLY | O_CLOEXEC);
1ff636
+        if (fd < 0)
1ff636
                 return false;
1ff636
-        if (fread(&config, sizeof(config), 1, f) != 1)
1ff636
+        if (read(fd, &config, sizeof(config)) != sizeof(config))
1ff636
                 return false;
1ff636
 
1ff636
         /* bit 0-6 header type, bit 7 multi/single function device */