Skip to content

Commit 6aed7b9

Browse files
committed
Merge tag 'thermal-6.9-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull thermal control fixes from Rafael Wysocki: "Fix a memory leak and a few locking issues (that may cause the kernel to crash in principle if all goes wrong) in the thermal debug code introduced during the 6.8 development cycle" * tag 'thermal-6.9-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: thermal/debugfs: Prevent use-after-free from occurring after cdev removal thermal/debugfs: Fix two locking issues with thermal zone debug thermal/debugfs: Free all thermal zone debug memory on zone removal
2 parents 545c494 + d351eb0 commit 6aed7b9

File tree

1 file changed

+45
-14
lines changed

1 file changed

+45
-14
lines changed

drivers/thermal/thermal_debugfs.c

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,13 @@ struct tz_episode {
139139
* we keep track of the current position in the history array.
140140
*
141141
* @tz_episodes: a list of thermal mitigation episodes
142+
* @tz: thermal zone this object belongs to
142143
* @trips_crossed: an array of trip points crossed by id
143144
* @nr_trips: the number of trip points currently being crossed
144145
*/
145146
struct tz_debugfs {
146147
struct list_head tz_episodes;
148+
struct thermal_zone_device *tz;
147149
int *trips_crossed;
148150
int nr_trips;
149151
};
@@ -503,15 +505,23 @@ void thermal_debug_cdev_add(struct thermal_cooling_device *cdev)
503505
*/
504506
void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev)
505507
{
506-
struct thermal_debugfs *thermal_dbg = cdev->debugfs;
508+
struct thermal_debugfs *thermal_dbg;
507509

508-
if (!thermal_dbg)
510+
mutex_lock(&cdev->lock);
511+
512+
thermal_dbg = cdev->debugfs;
513+
if (!thermal_dbg) {
514+
mutex_unlock(&cdev->lock);
509515
return;
516+
}
517+
518+
cdev->debugfs = NULL;
519+
520+
mutex_unlock(&cdev->lock);
510521

511522
mutex_lock(&thermal_dbg->lock);
512523

513524
thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg);
514-
cdev->debugfs = NULL;
515525

516526
mutex_unlock(&thermal_dbg->lock);
517527

@@ -716,8 +726,7 @@ void thermal_debug_update_temp(struct thermal_zone_device *tz)
716726

717727
static void *tze_seq_start(struct seq_file *s, loff_t *pos)
718728
{
719-
struct thermal_zone_device *tz = s->private;
720-
struct thermal_debugfs *thermal_dbg = tz->debugfs;
729+
struct thermal_debugfs *thermal_dbg = s->private;
721730
struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg;
722731

723732
mutex_lock(&thermal_dbg->lock);
@@ -727,24 +736,23 @@ static void *tze_seq_start(struct seq_file *s, loff_t *pos)
727736

728737
static void *tze_seq_next(struct seq_file *s, void *v, loff_t *pos)
729738
{
730-
struct thermal_zone_device *tz = s->private;
731-
struct thermal_debugfs *thermal_dbg = tz->debugfs;
739+
struct thermal_debugfs *thermal_dbg = s->private;
732740
struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg;
733741

734742
return seq_list_next(v, &tz_dbg->tz_episodes, pos);
735743
}
736744

737745
static void tze_seq_stop(struct seq_file *s, void *v)
738746
{
739-
struct thermal_zone_device *tz = s->private;
740-
struct thermal_debugfs *thermal_dbg = tz->debugfs;
747+
struct thermal_debugfs *thermal_dbg = s->private;
741748

742749
mutex_unlock(&thermal_dbg->lock);
743750
}
744751

745752
static int tze_seq_show(struct seq_file *s, void *v)
746753
{
747-
struct thermal_zone_device *tz = s->private;
754+
struct thermal_debugfs *thermal_dbg = s->private;
755+
struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz;
748756
struct thermal_trip *trip;
749757
struct tz_episode *tze;
750758
const char *type;
@@ -810,6 +818,8 @@ void thermal_debug_tz_add(struct thermal_zone_device *tz)
810818

811819
tz_dbg = &thermal_dbg->tz_dbg;
812820

821+
tz_dbg->tz = tz;
822+
813823
tz_dbg->trips_crossed = kzalloc(sizeof(int) * tz->num_trips, GFP_KERNEL);
814824
if (!tz_dbg->trips_crossed) {
815825
thermal_debugfs_remove_id(thermal_dbg);
@@ -818,23 +828,44 @@ void thermal_debug_tz_add(struct thermal_zone_device *tz)
818828

819829
INIT_LIST_HEAD(&tz_dbg->tz_episodes);
820830

821-
debugfs_create_file("mitigations", 0400, thermal_dbg->d_top, tz, &tze_fops);
831+
debugfs_create_file("mitigations", 0400, thermal_dbg->d_top,
832+
thermal_dbg, &tze_fops);
822833

823834
tz->debugfs = thermal_dbg;
824835
}
825836

826837
void thermal_debug_tz_remove(struct thermal_zone_device *tz)
827838
{
828-
struct thermal_debugfs *thermal_dbg = tz->debugfs;
839+
struct thermal_debugfs *thermal_dbg;
840+
struct tz_episode *tze, *tmp;
841+
struct tz_debugfs *tz_dbg;
842+
int *trips_crossed;
829843

830-
if (!thermal_dbg)
844+
mutex_lock(&tz->lock);
845+
846+
thermal_dbg = tz->debugfs;
847+
if (!thermal_dbg) {
848+
mutex_unlock(&tz->lock);
831849
return;
850+
}
851+
852+
tz->debugfs = NULL;
853+
854+
mutex_unlock(&tz->lock);
855+
856+
tz_dbg = &thermal_dbg->tz_dbg;
832857

833858
mutex_lock(&thermal_dbg->lock);
834859

835-
tz->debugfs = NULL;
860+
trips_crossed = tz_dbg->trips_crossed;
861+
862+
list_for_each_entry_safe(tze, tmp, &tz_dbg->tz_episodes, node) {
863+
list_del(&tze->node);
864+
kfree(tze);
865+
}
836866

837867
mutex_unlock(&thermal_dbg->lock);
838868

839869
thermal_debugfs_remove_id(thermal_dbg);
870+
kfree(trips_crossed);
840871
}

0 commit comments

Comments
 (0)