diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index d1105b7ae437..5d53bfcdf726 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -2172,18 +2172,19 @@ static void gpio_v2_line_info_changed_to_v1( #endif /* CONFIG_GPIO_CDEV_V1 */ -static void gpio_desc_to_lineinfo(struct gpio_desc *desc, - struct gpio_v2_line_info *info, bool atomic) +static int gpio_desc_to_lineinfo(struct gpio_desc *desc, + struct gpio_v2_line_info *info, bool atomic) { u32 debounce_period_us; unsigned long dflags; const char *label; + memset(info, 0, sizeof(*info)); + CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; - memset(info, 0, sizeof(*info)); info->offset = gpiod_hwgpio(desc); if (desc->name) @@ -2258,6 +2259,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, debounce_period_us; info->num_attrs++; } + + return 0; } struct gpio_chardev_data { @@ -2309,6 +2312,7 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip, struct gpio_desc *desc; struct gpioline_info lineinfo; struct gpio_v2_line_info lineinfo_v2; + int ret; if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; @@ -2326,7 +2330,10 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip, return -EBUSY; } - gpio_desc_to_lineinfo(desc, &lineinfo_v2, false); + ret = gpio_desc_to_lineinfo(desc, &lineinfo_v2, false); + if (ret) + return ret; + gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { @@ -2344,6 +2351,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, { struct gpio_desc *desc; struct gpio_v2_line_info lineinfo; + int ret; if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; @@ -2363,7 +2371,10 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, if (test_and_set_bit(lineinfo.offset, cdev->watched_lines)) return -EBUSY; } - gpio_desc_to_lineinfo(desc, &lineinfo, false); + + ret = gpio_desc_to_lineinfo(desc, &lineinfo, false); + if (ret) + return ret; if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { if (watch) @@ -2489,6 +2500,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, struct lineinfo_changed_ctx *ctx; struct gpio_desc *desc = data; struct file *fp; + int ret; if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines)) return NOTIFY_DONE; @@ -2519,7 +2531,13 @@ static int lineinfo_changed_notify(struct notifier_block *nb, ctx->chg.event_type = action; ctx->chg.timestamp_ns = ktime_get_ns(); - gpio_desc_to_lineinfo(desc, &ctx->chg.info, true); + + ret = gpio_desc_to_lineinfo(desc, &ctx->chg.info, true); + if (ret) { + fput(fp); + return NOTIFY_DONE; + } + /* Keep the GPIO device alive until we emit the event. */ ctx->gdev = gpio_device_get(desc->gdev); ctx->cdev = cdev;