mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 12:03:54 +02:00
ALSA: timer: avoid past-the-end iterator in snd_timer_dev_register()
snd_timer_dev_register() walks snd_timer_list looking for the
ordered insertion point and on loop fall-through passes
&timer1->device_list to list_add_tail():
list_for_each_entry(timer1, &snd_timer_list, device_list) {
...
break; /* on found-position */
...
}
list_add_tail(&timer->device_list, &timer1->device_list);
When the loop walks all entries without break, timer1 is
past-the-end. &timer1->device_list aliases &snd_timer_list (the
list head) via container_of offset cancellation, so the insert
lands at the list tail. That is the intended behaviour, but the
access is undefined per C11 even though it works in practice.
Track an explicit insert_before pointer initialised to the list
head and overwritten to &timer1->device_list only when the loop
breaks early. The observable behaviour is unchanged.
Fixes: 9244b2c307 ("[ALSA] alsa core: convert to list_for_each_entry*")
Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
Link: https://patch.msgid.link/20260518194023.1667857-2-maoyixie.tju@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
532d06c646
commit
34ed239561
|
|
@ -1007,6 +1007,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
|||
{
|
||||
struct snd_timer *timer = dev->device_data;
|
||||
struct snd_timer *timer1;
|
||||
struct list_head *insert_before = &snd_timer_list;
|
||||
|
||||
if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
|
||||
return -ENXIO;
|
||||
|
|
@ -1016,28 +1017,36 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
|||
|
||||
guard(mutex)(®ister_mutex);
|
||||
list_for_each_entry(timer1, &snd_timer_list, device_list) {
|
||||
if (timer1->tmr_class > timer->tmr_class)
|
||||
if (timer1->tmr_class > timer->tmr_class) {
|
||||
insert_before = &timer1->device_list;
|
||||
break;
|
||||
}
|
||||
if (timer1->tmr_class < timer->tmr_class)
|
||||
continue;
|
||||
if (timer1->card && timer->card) {
|
||||
if (timer1->card->number > timer->card->number)
|
||||
if (timer1->card->number > timer->card->number) {
|
||||
insert_before = &timer1->device_list;
|
||||
break;
|
||||
}
|
||||
if (timer1->card->number < timer->card->number)
|
||||
continue;
|
||||
}
|
||||
if (timer1->tmr_device > timer->tmr_device)
|
||||
if (timer1->tmr_device > timer->tmr_device) {
|
||||
insert_before = &timer1->device_list;
|
||||
break;
|
||||
}
|
||||
if (timer1->tmr_device < timer->tmr_device)
|
||||
continue;
|
||||
if (timer1->tmr_subdevice > timer->tmr_subdevice)
|
||||
if (timer1->tmr_subdevice > timer->tmr_subdevice) {
|
||||
insert_before = &timer1->device_list;
|
||||
break;
|
||||
}
|
||||
if (timer1->tmr_subdevice < timer->tmr_subdevice)
|
||||
continue;
|
||||
/* conflicts.. */
|
||||
return -EBUSY;
|
||||
}
|
||||
list_add_tail(&timer->device_list, &timer1->device_list);
|
||||
list_add_tail(&timer->device_list, insert_before);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user