From: Kent Gibson <warthog618@gmail.com>
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>
[Bartosz: rebased on top of the fix for empty GPIO labels]
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
drivers/gpio/gpiolib-cdev.c | 47 +++++++++++++++++++++----------------
1 file changed, 27 insertions(+), 20 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 1426cc1c4a28..6fe978535047 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -728,6 +728,25 @@ static u32 line_event_id(int level)
GPIO_V2_LINE_EVENT_FALLING_EDGE;
}
+static inline char *make_irq_label(const char *orig)
+{
+ char *new;
+
+ if (!orig)
+ return NULL;
+
+ new = kstrdup_and_replace(orig, '/', ':', GFP_KERNEL);
+ if (!new)
+ return ERR_PTR(-ENOMEM);
+
+ return new;
+}
+
+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 +1034,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 +1057,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);
+ if (IS_ERR(label))
+ return -ENOMEM;
+
irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
ret = request_irq(irq, debounce_irq_handler, irqflags,
line->req->label, line);
- if (ret)
+ if (ret) {
+ free_irq_label(label);
return ret;
+ }
line->irq = irq;
} else {
ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH);
@@ -1083,25 +1109,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)
-{
- char *new;
-
- if (!orig)
- return NULL;
-
- new = kstrdup_and_replace(orig, '/', ':', GFP_KERNEL);
- if (!new)
- return ERR_PTR(-ENOMEM);
-
- return new;
-}
-
-static inline void free_irq_label(const char *label)
-{
- kfree(label);
-}
-
static void edge_detector_stop(struct line *line)
{
if (line->irq) {
--
2.40.1
On Thu, Apr 04, 2024 at 11:33:28AM +0200, Bartosz Golaszewski wrote:
> From: Kent Gibson <warthog618@gmail.com>
>
> 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().
...
> +static inline char *make_irq_label(const char *orig)
> +{
> + char *new;
> +
> + if (!orig)
> + return NULL;
> +
> + new = kstrdup_and_replace(orig, '/', ':', GFP_KERNEL);
> + if (!new)
> + return ERR_PTR(-ENOMEM);
> +
> + return new;
> +}
> +
> +static inline void free_irq_label(const char *label)
> +{
> + kfree(label);
> +}
First of all this could have been done in the previous patch already, but okay.
...
> + label = make_irq_label(line->req->label);
> + if (IS_ERR(label))
> + return -ENOMEM;
> +
> irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
> ret = request_irq(irq, debounce_irq_handler, irqflags,
> line->req->label, line);
But the main point how does this change fix anything?
Shouldn't be
- line->req->label, line);
+ label, line);
?
> + if (ret) {
> + free_irq_label(label);
> return ret;
> + }
--
With Best Regards,
Andy Shevchenko
On Thu, Apr 4, 2024 at 5:36 PM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Thu, Apr 04, 2024 at 11:33:28AM +0200, Bartosz Golaszewski wrote:
> > From: Kent Gibson <warthog618@gmail.com>
> >
> > 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().
>
> ...
>
> > +static inline char *make_irq_label(const char *orig)
> > +{
> > + char *new;
> > +
> > + if (!orig)
> > + return NULL;
> > +
> > + new = kstrdup_and_replace(orig, '/', ':', GFP_KERNEL);
> > + if (!new)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + return new;
> > +}
> > +
> > +static inline void free_irq_label(const char *label)
> > +{
> > + kfree(label);
> > +}
>
> First of all this could have been done in the previous patch already, but okay.
>
> ...
>
> > + label = make_irq_label(line->req->label);
> > + if (IS_ERR(label))
> > + return -ENOMEM;
> > +
> > irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
> > ret = request_irq(irq, debounce_irq_handler, irqflags,
> > line->req->label, line);
>
> But the main point how does this change fix anything?
>
> Shouldn't be
>
> - line->req->label, line);
> + label, line);
It should, I badly copy-pasted Kent's correct code. Thanks, I fixed it in tree.
Bart
>
> ?
>
> > + if (ret) {
> > + free_irq_label(label);
> > return ret;
> > + }
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
© 2016 - 2026 Red Hat, Inc.