Re: [PATCH 1/2] gpio: cdev: fix missed label sanitizing in debounce_setup()

Bartosz Golaszewski
2024-04-04T08:20:42Z

On Wed, Apr 3, 2024 at 3:15 PM Kent Gibson <warthog618@gmail.com> wrote:
>
> When adding sanitization of the label, the path through
> edge_detector_setup() that leads to debounce_setup() was overlooked.
> A request taking this path does not allocate a new label and the
> request label is freed twice when the request is released, resulting
> in memory corruption.
>
> Add label sanitization to debounce_setup().
>
> Cc: stable@vger.kernel.org
> Fixes: b34490879baa ("gpio: cdev: sanitize the label before requesting the interrupt")
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> drivers/gpio/gpiolib-cdev.c | 31 +++++++++++++++++++------------
> 1 file changed, 19 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
> index fa9635610251..f4c2da2041e5 100644
> --- a/drivers/gpio/gpiolib-cdev.c
> +++ b/drivers/gpio/gpiolib-cdev.c
> @@ -728,6 +728,16 @@ static u32 line_event_id(int level)
> GPIO_V2_LINE_EVENT_FALLING_EDGE;
> }
>
> +static inline char *make_irq_label(const char *orig)
> +{
> + return kstrdup_and_replace(orig, '/', ':', GFP_KERNEL);
> +}
> +
> +static inline void free_irq_label(const char *label)
> +{
> + kfree(label);
> +}
> +
> #ifdef CONFIG_HTE
>
> static enum hte_return process_hw_ts_thread(void *p)
> @@ -1015,6 +1025,7 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us)
> {
> unsigned long irqflags;
> int ret, level, irq;
> + char *label;
>
> /* try hardware */
> ret = gpiod_set_debounce(line->desc, debounce_period_us);
> @@ -1037,11 +1048,17 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us)
> if (irq < 0)
> return -ENXIO;
>
> + label = make_irq_label(line->req->label);

Now that I look at the actual patch, I don't really like it. We
introduce a bug just to fix it a commit later. Such things have been
frowned upon in the past.

Let me shuffle the code a bit, I'll try to make it a bit more correct.

Bart

> + if (!label)
> + return -ENOMEM;
> +
> irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
> ret = request_irq(irq, debounce_irq_handler, irqflags,
> - line->req->label, line);
> - if (ret)
> + label, line);
> + if (ret) {
> + free_irq_label(label);
> return ret;
> + }
> line->irq = irq;
> } else {
> ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH);
> @@ -1083,16 +1100,6 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc,
> return 0;
> }
>
> -static inline char *make_irq_label(const char *orig)
> -{
> - return kstrdup_and_replace(orig, '/', ':', GFP_KERNEL);
> -}
> -
> -static inline void free_irq_label(const char *label)
> -{
> - kfree(label);
> -}
> -
> static void edge_detector_stop(struct line *line)
> {
> if (line->irq) {
> --
> 2.39.2
>