On Thu, Dec 1, 2022 at 1:01 PM Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> wrote: > > On Thu, Dec 01, 2022 at 09:33:35AM +0100, Bartosz Golaszewski wrote: > > From: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxx> > > > > While any of the GPIO cdev syscalls is in progress, the kernel can call > > gpiochip_remove() (for instance, when a USB GPIO expander is disconnected) > > which will set gdev->chip to NULL after which any subsequent access will > > cause a crash. > > > > To avoid that: use an RW-semaphore in which the syscalls take it for > > reading (so that we don't needlessly prohibit the user-space from calling > > syscalls simultaneously) while gpiochip_remove() takes it for writing so > > that it can only happen once all syscalls return. > > > > Fixes: d7c51b47ac11 ("gpio: userspace ABI for reading/writing GPIO lines") > > Fixes: 3c0d9c635ae2 ("gpiolib: cdev: support GPIO_V2_GET_LINE_IOCTL and GPIO_V2_LINE_GET_VALUES_IOCTL") > > Fixes: aad955842d1c ("gpiolib: cdev: support GPIO_V2_GET_LINEINFO_IOCTL and GPIO_V2_GET_LINEINFO_WATCH_IOCTL") > > Fixes: a54756cb24ea ("gpiolib: cdev: support GPIO_V2_LINE_SET_CONFIG_IOCTL") > > Fixes: 7b8e00d98168 ("gpiolib: cdev: support GPIO_V2_LINE_SET_VALUES_IOCTL") > > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxx> > > Reviewed-by: Kent Gibson <warthog618@xxxxxxxxx> > > Reviewed-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> > > --- > > drivers/gpio/gpiolib-cdev.c | 166 +++++++++++++++++++++++++++++++----- > > drivers/gpio/gpiolib.c | 4 + > > drivers/gpio/gpiolib.h | 5 ++ > > 3 files changed, 153 insertions(+), 22 deletions(-) > > > > diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c > > index 911d91668903..18c5e70ee7de 100644 > > --- a/drivers/gpio/gpiolib-cdev.c > > +++ b/drivers/gpio/gpiolib-cdev.c > > @@ -84,6 +84,53 @@ struct linehandle_state { > > GPIOHANDLE_REQUEST_OPEN_DRAIN | \ > > GPIOHANDLE_REQUEST_OPEN_SOURCE) > > > > +typedef __poll_t (*poll_fn)(struct file *, struct poll_table_struct *); > > +typedef long (*ioctl_fn)(struct file *, unsigned int, unsigned long); > > +typedef ssize_t (*read_fn)(struct file *, char __user *, > > + size_t count, loff_t *); > > + > > +static __poll_t call_poll_locked(struct file *file, > > + struct poll_table_struct *wait, > > + struct gpio_device *gdev, poll_fn func) > > +{ > > + __poll_t ret; > > + > > + if (!down_read_trylock(&gdev->sem)) > > > + return 0; > > EPOLLHUP? > Or even EPOLLERR | EPOLLHUP. Sorry in advance for the noise but I really want to get those fixes in this week, so I'll send a new iteration shortly. Bart