pwm: Ensure that pwm_chips are allocated using pwmchip_alloc()
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Wed, 14 Feb 2024 09:33:28 +0000 (10:33 +0100)
committerUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Fri, 26 Apr 2024 19:29:16 +0000 (21:29 +0200)
Memory holding a struct device must not be freed before the reference
count drops to zero. So a struct pwm_chip must not live in memory
freed by a driver on unbind. All in-tree drivers were fixed accordingly,
but as out-of-tree drivers, that were not adapted, still compile fine,
catch these in pwmchip_add().

Link: https://lore.kernel.org/r/35f5b229c98f78b2f6ce2397259a4a936be477c0.1707900770.git.u.kleine-koenig@pengutronix.de
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
drivers/pwm/core.c
include/linux/pwm.h

index 403525cc17833c18271d555e1469814845ddd45d..d3f475eca97f339748de628bbf21b8cd73df50de 100644 (file)
@@ -481,6 +481,7 @@ struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t
 
        chip->dev = parent;
        chip->npwm = npwm;
+       chip->uses_pwmchip_alloc = true;
 
        pwmchip_set_drvdata(chip, pwmchip_priv(chip));
 
@@ -561,6 +562,15 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
        if (!chip || !pwmchip_parent(chip) || !chip->ops || !chip->npwm)
                return -EINVAL;
 
+       /*
+        * a struct pwm_chip must be allocated using (devm_)pwmchip_alloc,
+        * otherwise the embedded struct device might disappear too early
+        * resulting in memory corruption.
+        * Catch drivers that were not converted appropriately.
+        */
+       if (!chip->uses_pwmchip_alloc)
+               return -EINVAL;
+
        if (!pwm_ops_check(chip))
                return -EINVAL;
 
index 4a6568dfdf3fa606f7f9c682067b116fc594e2a7..94a642a888179649d1a11062722478ec107dd5fd 100644 (file)
@@ -272,6 +272,7 @@ struct pwm_ops {
  * @npwm: number of PWMs controlled by this chip
  * @of_xlate: request a PWM device given a device tree PWM specifier
  * @atomic: can the driver's ->apply() be called in atomic context
+ * @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this chip
  * @driver_data: Private pointer for driver specific info
  * @pwms: array of PWM devices allocated by the framework
  */
@@ -287,6 +288,7 @@ struct pwm_chip {
        bool atomic;
 
        /* only used internally by the PWM framework */
+       bool uses_pwmchip_alloc;
        void *driver_data;
        struct pwm_device *pwms;
 };