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); + 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) {
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
On Thu, Apr 04, 2024 at 10:20:29AM +0200, Bartosz Golaszewski wrote:
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.
The debounce_setup() oversight bug is the more severe, so it makes more sense to me to fix it first. But then I my preferred solution would be to pull the original patch and submit a corrected patch that merges all three, so no bugs, but I assume that isn't an option.
Cheers, Kent.
On Thu, Apr 4, 2024 at 12:59 PM Kent Gibson warthog618@gmail.com wrote:
On Thu, Apr 04, 2024 at 10:20:29AM +0200, Bartosz Golaszewski wrote:
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.
The debounce_setup() oversight bug is the more severe, so it makes more sense to me to fix it first. But then I my preferred solution would be to pull the original patch and submit a corrected patch that merges all three, so no bugs, but I assume that isn't an option.
Nah, let's not needlessly rebase it. Most I can do is merge the two but they are really functionally separate so I'd keep it as is in v2.
Bart
linux-stable-mirror@lists.linaro.org