Blob Blame History Raw
From 210ec6353d3cab2029e1eb160671fea918c97814 Mon Sep 17 00:00:00 2001
From: "Jason S. McMullan" <jason.mcmullan@gmail.com>
Date: Fri, 22 May 2015 20:30:01 +0200
Subject: [PATCH] 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.

(cherry picked from commit 0454229c100a2113ba82df55703436d6cb2c492b)

Cherry-picked from: 0454229
Resolves: #1222517
---
 src/udev/udev-builtin-net_id.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 66474f7728..dd2886caf2 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -91,6 +91,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <string.h>
 #include <errno.h>
 #include <net/if.h>
@@ -166,15 +167,15 @@ 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) {
-        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_close_ int fd = -1;
         const char *filename;
         uint8_t config[64];
 
         filename = strjoina(udev_device_get_syspath(dev), "/config");
-        f = fopen(filename, "re");
-        if (!f)
+        fd = open(filename, O_RDONLY | O_CLOEXEC);
+        if (fd < 0)
                 return false;
-        if (fread(&config, sizeof(config), 1, f) != 1)
+        if (read(fd, &config, sizeof(config)) != sizeof(config))
                 return false;
 
         /* bit 0-6 header type, bit 7 multi/single function device */