Skip to content

Commit 549f8ff

Browse files
committed
ALSA: hda: Fix UAF of leds class devs at unbinding
The LED class devices that are created by HD-audio codec drivers are registered via devm_led_classdev_register() and associated with the HD-audio codec device. Unfortunately, it turned out that the devres release doesn't work for this case; namely, since the codec resource release happens before the devm call chain, it triggers a NULL dereference or a UAF for a stale set_brightness_delay callback. For fixing the bug, this patch changes the LED class device register and unregister in a manual manner without devres, keeping the instances in hda_gen_spec. Reported-by: Alexander Sergeyev <[email protected]> Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent e783362 commit 549f8ff

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

sound/pci/hda/hda_generic.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
9191
free_kctls(spec);
9292
snd_array_free(&spec->paths);
9393
snd_array_free(&spec->loopback_list);
94+
#ifdef CONFIG_SND_HDA_GENERIC_LEDS
95+
if (spec->led_cdevs[LED_AUDIO_MUTE])
96+
led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
97+
if (spec->led_cdevs[LED_AUDIO_MICMUTE])
98+
led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
99+
#endif
94100
}
95101

96102
/*
@@ -3922,7 +3928,10 @@ static int create_mute_led_cdev(struct hda_codec *codec,
39223928
enum led_brightness),
39233929
bool micmute)
39243930
{
3931+
struct hda_gen_spec *spec = codec->spec;
39253932
struct led_classdev *cdev;
3933+
int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
3934+
int err;
39263935

39273936
cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
39283937
if (!cdev)
@@ -3932,10 +3941,14 @@ static int create_mute_led_cdev(struct hda_codec *codec,
39323941
cdev->max_brightness = 1;
39333942
cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
39343943
cdev->brightness_set_blocking = callback;
3935-
cdev->brightness = ledtrig_audio_get(micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE);
3944+
cdev->brightness = ledtrig_audio_get(idx);
39363945
cdev->flags = LED_CORE_SUSPENDRESUME;
39373946

3938-
return devm_led_classdev_register(&codec->core.dev, cdev);
3947+
err = led_classdev_register(&codec->core.dev, cdev);
3948+
if (err < 0)
3949+
return err;
3950+
spec->led_cdevs[idx] = cdev;
3951+
return 0;
39393952
}
39403953

39413954
/**

sound/pci/hda/hda_generic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ struct hda_gen_spec {
294294
struct hda_jack_callback *cb);
295295
void (*mic_autoswitch_hook)(struct hda_codec *codec,
296296
struct hda_jack_callback *cb);
297+
298+
/* leds */
299+
struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
297300
};
298301

299302
/* values for add_stereo_mix_input flag */

0 commit comments

Comments
 (0)