From ff917923f4fb9c83717ba135ee47d7e4c1567bb7 Mon Sep 17 00:00:00 2001 From: Muhammad Bilal Date: Tue, 28 Jul 2026 17:54:55 +0500 Subject: staging: rtl8723bs: fix OOB read in rtw_action_frame_parse() rtw_action_frame_parse() takes a frame_len parameter but never actually checks it before indexing into the frame body: const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); ... c = frame_body[0]; ... a = frame_body[1]; frame_body already points 24 bytes (sizeof(struct ieee80211_hdr_3addr)) into frame, so reading frame_body[0] and frame_body[1] requires frame_len >= 26. A management action frame shorter than that (e.g. exactly 24 bytes, the minimum a malicious peer can send) causes a 1-2 byte out-of-bounds read. This is reachable from rtw_cfg80211_monitor_if_xmit_entry() and cfg80211_rtw_mgmt_tx() in ioctl_cfg80211.c, both of which pass attacker/user-influenced frame buffers and lengths straight through. Add the missing length check before frame_body is dereferenced. Fixes: 554c0a3abf216 ("staging: Add rtl8723bs sdio wifi driver") Cc: stable@vger.kernel.org Signed-off-by: Muhammad Bilal Link: https://patch.msgid.link/20260728125456.32359-3-meatuni001@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-syscon.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 drivers/leds/leds-syscon.c (limited to 'drivers/leds/leds-syscon.c') diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c new file mode 100644 index 000000000..d633ad519 --- /dev/null +++ b/drivers/leds/leds-syscon.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Generic Syscon LEDs Driver + * + * Copyright (c) 2014, Linaro Limited + * Author: Linus Walleij + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct syscon_led - state container for syscon based LEDs + * @cdev: LED class device for this LED + * @map: regmap to access the syscon device backing this LED + * @offset: the offset into the syscon regmap for the LED register + * @mask: the bit in the register corresponding to the LED + * @state: current state of the LED + */ +struct syscon_led { + struct led_classdev cdev; + struct regmap *map; + u32 offset; + u32 mask; + bool state; +}; + +static void syscon_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct syscon_led *sled = + container_of(led_cdev, struct syscon_led, cdev); + u32 val; + int ret; + + if (value == LED_OFF) { + val = 0; + sled->state = false; + } else { + val = sled->mask; + sled->state = true; + } + + ret = regmap_update_bits(sled->map, sled->offset, sled->mask, val); + if (ret < 0) + dev_err(sled->cdev.dev, "error updating LED status\n"); +} + +static int syscon_led_probe(struct platform_device *pdev) +{ + struct led_init_data init_data = {}; + struct device *dev = &pdev->dev; + struct device_node *np = dev_of_node(dev); + struct device *parent; + struct regmap *map; + struct syscon_led *sled; + enum led_default_state state; + u32 value; + int ret; + + parent = dev->parent; + if (!parent) { + dev_err(dev, "no parent for syscon LED\n"); + return -ENODEV; + } + map = syscon_node_to_regmap(dev_of_node(parent)); + if (IS_ERR(map)) { + dev_err(dev, "no regmap for syscon LED parent\n"); + return PTR_ERR(map); + } + + sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL); + if (!sled) + return -ENOMEM; + + sled->map = map; + + if (of_property_read_u32(np, "reg", &sled->offset) && + of_property_read_u32(np, "offset", &sled->offset)) + return -EINVAL; + if (of_property_read_u32(np, "mask", &sled->mask)) + return -EINVAL; + + init_data.fwnode = of_fwnode_handle(np); + + state = led_init_default_state_get(init_data.fwnode); + switch (state) { + case LEDS_DEFSTATE_ON: + ret = regmap_update_bits(map, sled->offset, sled->mask, sled->mask); + if (ret < 0) + return ret; + sled->state = true; + break; + case LEDS_DEFSTATE_KEEP: + ret = regmap_read(map, sled->offset, &value); + if (ret < 0) + return ret; + sled->state = !!(value & sled->mask); + break; + default: + ret = regmap_update_bits(map, sled->offset, sled->mask, 0); + if (ret < 0) + return ret; + sled->state = false; + } + sled->cdev.brightness_set = syscon_led_set; + + ret = devm_led_classdev_register_ext(dev, &sled->cdev, &init_data); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, sled); + dev_info(dev, "registered LED %s\n", sled->cdev.name); + + return 0; +} + +static const struct of_device_id of_syscon_leds_match[] = { + { .compatible = "register-bit-led", }, + {}, +}; + +static struct platform_driver syscon_led_driver = { + .probe = syscon_led_probe, + .driver = { + .name = "leds-syscon", + .of_match_table = of_syscon_leds_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(syscon_led_driver); -- cgit v1.3.1