aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2020-02-06 20:13:58 +0200
committerBartosz Golaszewski <bgolaszewski@baylibre.com>2020-02-07 13:59:36 +0100
commit56ae2a701144b9a1dd5c2b57c1d4b51d6e3c4e69 (patch)
treeff15a1618eabe6b2ca5fc78d30cda5d84a07b61c
parent33adcd100cb6bc4258ae464127213c3bb9f66785 (diff)
downloadlibgpiod-56ae2a701144b9a1dd5c2b57c1d4b51d6e3c4e69.tar.gz
core: relax gpiod_chip_open() for symbolic links
User may ask device helper tool, for example, udev, to create a specific symbolic link to a device node. GPIO chip character device node is not exceptional. However, libgpiod in the commit d9b1c1f14c6b ("core: harden gpiod_chip_open()") went way too far in the hardening device node check. Relax that hardening for symbolic link to fix the regression. Reproducer: % gpioinfo /dev/gpiochip5 gpiochip5 - 16 lines: line 0: "MUX33_DIR" "uart1-rx-oe" output active-high [used] ... % ln -sf /dev/gpiochip5 /dev/MyGPIO_5 % gpioinfo /dev/MyGPIO_5 gpioinfo: looking up chip /dev/MyGPIO_5: Inappropriate ioctl for device Link: https://stackoverflow.com/questions/60057494/gpio-issue-with-sym-link Fixes: d9b1c1f14c6b ("core: harden gpiod_chip_open()") Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
-rw-r--r--lib/core.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/lib/core.c b/lib/core.c
index 7ddb568f..95826e1b 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -10,6 +10,7 @@
#include <errno.h>
#include <fcntl.h>
#include <gpiod.h>
+#include <limits.h>
#include <linux/gpio.h>
#include <poll.h>
#include <stdint.h>
@@ -62,7 +63,7 @@ struct gpiod_chip {
static bool is_gpiochip_cdev(const char *path)
{
- char *name, *pathcpy, *sysfsp, sysfsdev[16], devstr[16];
+ char *name, *realname, *sysfsp, sysfsdev[16], devstr[16];
struct stat statbuf;
bool ret = false;
int rv, fd;
@@ -72,6 +73,19 @@ static bool is_gpiochip_cdev(const char *path)
if (rv)
goto out;
+ /*
+ * Is it a symbolic link? We have to resolve symbolic link before
+ * checking the rest.
+ */
+ realname = S_ISLNK(statbuf.st_mode) ? realpath(path, NULL)
+ : strdup(path);
+ if (realname == NULL)
+ goto out;
+
+ rv = stat(realname, &statbuf);
+ if (rv)
+ goto out_free_realname;
+
/* Is it a character device? */
if (!S_ISCHR(statbuf.st_mode)) {
/*
@@ -81,20 +95,16 @@ static bool is_gpiochip_cdev(const char *path)
* libgpiod from before the introduction of this routine.
*/
errno = ENOTTY;
- goto out;
+ goto out_free_realname;
}
/* Get the basename. */
- pathcpy = strdup(path);
- if (!pathcpy)
- goto out;
-
- name = basename(pathcpy);
+ name = basename(realname);
/* Do we have a corresponding sysfs attribute? */
rv = asprintf(&sysfsp, "/sys/bus/gpio/devices/%s/dev", name);
if (rv < 0)
- goto out_free_pathcpy;
+ goto out_free_realname;
if (access(sysfsp, R_OK) != 0) {
/*
@@ -136,8 +146,8 @@ static bool is_gpiochip_cdev(const char *path)
out_free_sysfsp:
free(sysfsp);
-out_free_pathcpy:
- free(pathcpy);
+out_free_realname:
+ free(realname);
out:
return ret;
}