diff options
| author | Muhammad Bilal <meatuni001@gmail.com> | 2026-07-28 17:54:55 +0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-01 12:15:16 +0200 |
| commit | ff917923f4fb9c83717ba135ee47d7e4c1567bb7 (patch) | |
| tree | c38fd8fcf58e1937b17fdbc6518b6f8b797fc15a /drivers/video/backlight/rt4831-backlight.c | |
| download | linux-stable-ff917923f4fb9c83717ba135ee47d7e4c1567bb7.tar.gz linux-stable-ff917923f4fb9c83717ba135ee47d7e4c1567bb7.zip | |
staging: rtl8723bs: fix OOB read in rtw_action_frame_parse()grafted
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 <meatuni001@gmail.com>
Link: https://patch.msgid.link/20260728125456.32359-3-meatuni001@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/video/backlight/rt4831-backlight.c')
| -rw-r--r-- | drivers/video/backlight/rt4831-backlight.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/drivers/video/backlight/rt4831-backlight.c b/drivers/video/backlight/rt4831-backlight.c new file mode 100644 index 000000000..7ead75929 --- /dev/null +++ b/drivers/video/backlight/rt4831-backlight.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <dt-bindings/leds/rt4831-backlight.h> +#include <linux/backlight.h> +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> + +#define RT4831_REG_BLCFG 0x02 +#define RT4831_REG_BLDIML 0x04 +#define RT4831_REG_ENABLE 0x08 +#define RT4831_REG_BLOPT2 0x11 + +#define RT4831_BLMAX_BRIGHTNESS 2048 + +#define RT4831_BLOVP_MASK GENMASK(7, 5) +#define RT4831_BLOVP_SHIFT 5 +#define RT4831_BLPWMEN_MASK BIT(0) +#define RT4831_BLEN_MASK BIT(4) +#define RT4831_BLCH_MASK GENMASK(3, 0) +#define RT4831_BLDIML_MASK GENMASK(2, 0) +#define RT4831_BLDIMH_MASK GENMASK(10, 3) +#define RT4831_BLDIMH_SHIFT 3 +#define RT4831_BLOCP_MASK GENMASK(1, 0) + +#define RT4831_BLOCP_MINUA 900000 +#define RT4831_BLOCP_MAXUA 1800000 +#define RT4831_BLOCP_STEPUA 300000 + +struct rt4831_priv { + struct device *dev; + struct regmap *regmap; + struct backlight_device *bl; +}; + +static int rt4831_bl_update_status(struct backlight_device *bl_dev) +{ + struct rt4831_priv *priv = bl_get_data(bl_dev); + int brightness = backlight_get_brightness(bl_dev); + unsigned int enable = brightness ? RT4831_BLEN_MASK : 0; + u8 v[2]; + int ret; + + if (brightness) { + v[0] = (brightness - 1) & RT4831_BLDIML_MASK; + v[1] = ((brightness - 1) & RT4831_BLDIMH_MASK) >> RT4831_BLDIMH_SHIFT; + + ret = regmap_raw_write(priv->regmap, RT4831_REG_BLDIML, v, sizeof(v)); + if (ret) + return ret; + } + + return regmap_update_bits(priv->regmap, RT4831_REG_ENABLE, RT4831_BLEN_MASK, enable); + +} + +static int rt4831_bl_get_brightness(struct backlight_device *bl_dev) +{ + struct rt4831_priv *priv = bl_get_data(bl_dev); + unsigned int val; + u8 v[2]; + int ret; + + ret = regmap_read(priv->regmap, RT4831_REG_ENABLE, &val); + if (ret) + return ret; + + if (!(val & RT4831_BLEN_MASK)) + return 0; + + ret = regmap_raw_read(priv->regmap, RT4831_REG_BLDIML, v, sizeof(v)); + if (ret) + return ret; + + ret = (v[1] << RT4831_BLDIMH_SHIFT) + (v[0] & RT4831_BLDIML_MASK) + 1; + + return ret; +} + +static const struct backlight_ops rt4831_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = rt4831_bl_update_status, + .get_brightness = rt4831_bl_get_brightness, +}; + +static int rt4831_parse_backlight_properties(struct rt4831_priv *priv, + struct backlight_properties *bl_props) +{ + struct device *dev = priv->dev; + u8 propval; + u32 brightness, ocp_uA; + unsigned int val = 0; + int ret; + + /* common properties */ + ret = device_property_read_u32(dev, "max-brightness", &brightness); + if (ret) + brightness = RT4831_BLMAX_BRIGHTNESS; + + bl_props->max_brightness = min_t(u32, brightness, RT4831_BLMAX_BRIGHTNESS); + + ret = device_property_read_u32(dev, "default-brightness", &brightness); + if (ret) + brightness = bl_props->max_brightness; + + bl_props->brightness = min_t(u32, brightness, bl_props->max_brightness); + + /* vendor properties */ + if (device_property_read_bool(dev, "richtek,pwm-enable")) + val = RT4831_BLPWMEN_MASK; + + ret = regmap_update_bits(priv->regmap, RT4831_REG_BLCFG, RT4831_BLPWMEN_MASK, val); + if (ret) + return ret; + + ret = device_property_read_u8(dev, "richtek,bled-ovp-sel", &propval); + if (ret) + propval = RT4831_BLOVPLVL_21V; + + propval = min_t(u8, propval, RT4831_BLOVPLVL_29V); + ret = regmap_update_bits(priv->regmap, RT4831_REG_BLCFG, RT4831_BLOVP_MASK, + propval << RT4831_BLOVP_SHIFT); + if (ret) + return ret; + + /* + * This OCP level is used to protect and limit the inductor current. + * If inductor peak current reach the level, low-side MOSFET will be + * turned off. Meanwhile, the output channel current may be limited. + * To match the configured channel current, the inductor chosen must + * be higher than the OCP level. + * + * Not like the OVP level, the default 21V can be used in the most + * application. But if the chosen OCP level is smaller than needed, + * it will also affect the backlight channel output current to be + * smaller than the register setting. + */ + ret = device_property_read_u32(dev, "richtek,bled-ocp-microamp", + &ocp_uA); + if (!ret) { + ocp_uA = clamp_val(ocp_uA, RT4831_BLOCP_MINUA, + RT4831_BLOCP_MAXUA); + val = DIV_ROUND_UP(ocp_uA - RT4831_BLOCP_MINUA, + RT4831_BLOCP_STEPUA); + ret = regmap_update_bits(priv->regmap, RT4831_REG_BLOPT2, + RT4831_BLOCP_MASK, val); + if (ret) + return ret; + } + + ret = device_property_read_u8(dev, "richtek,channel-use", &propval); + if (ret) { + dev_err(dev, "richtek,channel-use DT property missing\n"); + return ret; + } + + if (!(propval & RT4831_BLCH_MASK)) { + dev_err(dev, "No channel specified\n"); + return -EINVAL; + } + + return regmap_update_bits(priv->regmap, RT4831_REG_ENABLE, RT4831_BLCH_MASK, propval); +} + +static int rt4831_bl_probe(struct platform_device *pdev) +{ + struct rt4831_priv *priv; + struct backlight_properties bl_props = { .type = BACKLIGHT_RAW, + .scale = BACKLIGHT_SCALE_LINEAR }; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = rt4831_parse_backlight_properties(priv, &bl_props); + if (ret) { + dev_err(&pdev->dev, "Failed to parse backlight properties\n"); + return ret; + } + + priv->bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, priv, + &rt4831_bl_ops, &bl_props); + if (IS_ERR(priv->bl)) { + dev_err(&pdev->dev, "Failed to register backlight\n"); + return PTR_ERR(priv->bl); + } + + backlight_update_status(priv->bl); + platform_set_drvdata(pdev, priv); + + return 0; +} + +static void rt4831_bl_remove(struct platform_device *pdev) +{ + struct rt4831_priv *priv = platform_get_drvdata(pdev); + struct backlight_device *bl_dev = priv->bl; + + bl_dev->props.brightness = 0; + backlight_update_status(priv->bl); +} + +static const struct of_device_id __maybe_unused rt4831_bl_of_match[] = { + { .compatible = "richtek,rt4831-backlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, rt4831_bl_of_match); + +static struct platform_driver rt4831_bl_driver = { + .driver = { + .name = "rt4831-backlight", + .of_match_table = rt4831_bl_of_match, + }, + .probe = rt4831_bl_probe, + .remove = rt4831_bl_remove, +}; +module_platform_driver(rt4831_bl_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT4831 Backlight Driver"); +MODULE_LICENSE("GPL v2"); |
