From a8e41a81909ef74faa38ef12ca35c5d83f7c56a5 Mon Sep 17 00:00:00 2001 From: Moritz Bruder Date: Sat, 17 Dec 2022 18:19:57 +0100 Subject: [PATCH] fbdevhw: Support symbolic links in fbdev_open Resolve symbolic links before the PCI device check in fbdev_open. Otherwise, opening device files that are symbolic links will fail. Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1419 Signed-off-by: Moritz Bruder --- hw/xfree86/fbdevhw/fbdevhw.c | 44 +++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/fbdevhw/fbdevhw.c b/hw/xfree86/fbdevhw/fbdevhw.c index 3d8b92e66..8d4e3c596 100644 --- a/hw/xfree86/fbdevhw/fbdevhw.c +++ b/hw/xfree86/fbdevhw/fbdevhw.c @@ -304,6 +304,31 @@ fbdev_open_pci(struct pci_device *pPci, char **namep) return -1; } +/* * + * Try to resolve a filename as symbolic link. If the file is not a link, the + * original filename is returned. NULL is returned if readlink raised an + * error. + */ +static const char * +resolve_link(const char *filename, char *resolve_buf, size_t resolve_buf_size) +{ + ssize_t len = readlink(filename, resolve_buf, resolve_buf_size - 1); + /* if it is a link resolve it */ + if (len >= 0) { + resolve_buf[len] = '\0'; + return resolve_buf; + } + else { + if (errno == EINVAL) { + return filename; + } + else { + // Have caller handle error condition. + return NULL; + } + } +} + static int fbdev_open(int scrnIndex, const char *dev, char **namep) { @@ -331,9 +356,26 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) /* only touch non-PCI devices on this path */ { + char device_path_buf[PATH_MAX]; char buf[PATH_MAX] = {0}; char *sysfs_path = NULL; - char *node = strrchr(dev, '/') + 1; + char const *real_dev = resolve_link(dev, device_path_buf, + sizeof(device_path_buf)); + if (real_dev == NULL) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Failed resolving symbolic link for device '%s': %s", + dev, strerror(errno)); + return -1; + } + + const char *node = strrchr(real_dev, '/'); + + if (node == NULL) { + node = real_dev; + } + else { + node++; + } if (asprintf(&sysfs_path, "/sys/class/graphics/%s", node) < 0 || readlink(sysfs_path, buf, sizeof(buf) - 1) < 0 ||