diff mbox series

input: button_kbd: gracefully handle buttons that fail probe

Message ID 20240411175244.937795-1-caleb.connolly@linaro.org
State Accepted
Commit 024c95392d5ab5414e455e6f92e06dd063296d77
Headers show
Series input: button_kbd: gracefully handle buttons that fail probe | expand

Commit Message

Caleb Connolly April 11, 2024, 5:52 p.m. UTC
If a button device fails to probe, it will still be added to the uclass
device list, and therefore will still be iterated over in
button_read_keys() resulting in a UAF on the buttons private data.

Resolve this by unbinding button devices that aren't active after
probing, and print a warning so it's clear that the button is broken.

Fixes: e8779962898e ("dm: input: add button_kbd driver")
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
 drivers/input/button_kbd.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

Comments

Tom Rini April 19, 2024, 1:57 a.m. UTC | #1
On Thu, 11 Apr 2024 19:52:37 +0200, Caleb Connolly wrote:

> If a button device fails to probe, it will still be added to the uclass
> device list, and therefore will still be iterated over in
> button_read_keys() resulting in a UAF on the buttons private data.
> 
> Resolve this by unbinding button devices that aren't active after
> probing, and print a warning so it's clear that the button is broken.
> 
> [...]

Applied to u-boot/master, thanks!
diff mbox series

Patch

diff --git a/drivers/input/button_kbd.c b/drivers/input/button_kbd.c
index 74fadfca8bb8..c73d3b18be9c 100644
--- a/drivers/input/button_kbd.c
+++ b/drivers/input/button_kbd.c
@@ -33,9 +33,10 @@  struct button_kbd_priv {
 static int button_kbd_start(struct udevice *dev)
 {
 	struct button_kbd_priv *priv = dev_get_priv(dev);
 	int i = 0;
-	struct udevice *button_gpio_devp;
+	struct udevice *button_gpio_devp, *next_devp;
+	struct uclass *uc;
 
 	uclass_foreach_dev_probe(UCLASS_BUTTON, button_gpio_devp) {
 		struct button_uc_plat *uc_plat = dev_get_uclass_plat(button_gpio_devp);
 		/* Ignore the top-level button node */
@@ -45,8 +46,23 @@  static int button_kbd_start(struct udevice *dev)
 		      uc_plat->label, i, button_gpio_devp->name);
 		i++;
 	}
 
+	if (uclass_get(UCLASS_BUTTON, &uc))
+		return -ENOENT;
+
+	/*
+	 * Unbind any buttons that failed to probe so we don't iterate over
+	 * them when polling.
+	 */
+	uclass_foreach_dev_safe(button_gpio_devp, next_devp, uc) {
+		if (!(dev_get_flags(button_gpio_devp) & DM_FLAG_ACTIVATED)) {
+			log_warning("Button %s failed to probe\n",
+				    button_gpio_devp->name);
+			device_unbind(button_gpio_devp);
+		}
+	}
+
 	priv->button_size = i;
 	priv->old_state = calloc(i, sizeof(int));
 
 	return 0;