Skip to content

Commit 067c2f4

Browse files
committed
Merge tag 'sound-4.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai: "We've got quite a few fixes at this time, and all are stable patches. syzkaller strikes back again (episode 19 or so), and we had to plug some holes in ALSA core part (mostly timer). In addition, a couple of FireWire audio fixes for the invalid copy user calls in locks, and a few quirks for HD-audio and USB-audio as usual are included" * tag 'sound-4.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: ALSA: rawmidi: Fix possible deadlock with virmidi registration ALSA: timer: Fix zero-division by continue of uninitialized instance ALSA: timer: fix NULL pointer dereference in read()/ioctl() race ALSA: fireworks: accessing to user space outside spinlock ALSA: firewire-tascam: accessing to user space outside spinlock ALSA: hda - Enable subwoofer on Dell Inspiron 7559 ALSA: hda - Add headset mic quirk for Dell Inspiron 5468 ALSA: usb-audio: Add sample rate inquiry quirk for B850V3 CP2114 ALSA: timer: fix NULL pointer dereference on memory allocation failure ALSA: timer: fix division by zero after SNDRV_TIMER_IOCTL_CONTINUE
2 parents e45eeb4 + 816f318 commit 067c2f4

File tree

9 files changed

+118
-50
lines changed

9 files changed

+118
-50
lines changed

sound/core/rawmidi.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,18 +1633,21 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
16331633
return -EBUSY;
16341634
}
16351635
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
1636+
mutex_unlock(&register_mutex);
16361637
err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
16371638
rmidi->card, rmidi->device,
16381639
&snd_rawmidi_f_ops, rmidi, &rmidi->dev);
16391640
if (err < 0) {
16401641
rmidi_err(rmidi, "unable to register\n");
1642+
mutex_lock(&register_mutex);
16411643
list_del(&rmidi->list);
16421644
mutex_unlock(&register_mutex);
16431645
return err;
16441646
}
16451647
if (rmidi->ops && rmidi->ops->dev_register &&
16461648
(err = rmidi->ops->dev_register(rmidi)) < 0) {
16471649
snd_unregister_device(&rmidi->dev);
1650+
mutex_lock(&register_mutex);
16481651
list_del(&rmidi->list);
16491652
mutex_unlock(&register_mutex);
16501653
return err;
@@ -1677,7 +1680,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
16771680
}
16781681
}
16791682
#endif /* CONFIG_SND_OSSEMUL */
1680-
mutex_unlock(&register_mutex);
16811683
sprintf(name, "midi%d", rmidi->device);
16821684
entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
16831685
if (entry) {

sound/core/timer.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#include <sound/initval.h>
3636
#include <linux/kmod.h>
3737

38+
/* internal flags */
39+
#define SNDRV_TIMER_IFLG_PAUSED 0x00010000
40+
3841
#if IS_ENABLED(CONFIG_SND_HRTIMER)
3942
#define DEFAULT_TIMER_LIMIT 4
4043
#else
@@ -294,8 +297,21 @@ int snd_timer_open(struct snd_timer_instance **ti,
294297
get_device(&timer->card->card_dev);
295298
timeri->slave_class = tid->dev_sclass;
296299
timeri->slave_id = slave_id;
297-
if (list_empty(&timer->open_list_head) && timer->hw.open)
298-
timer->hw.open(timer);
300+
301+
if (list_empty(&timer->open_list_head) && timer->hw.open) {
302+
int err = timer->hw.open(timer);
303+
if (err) {
304+
kfree(timeri->owner);
305+
kfree(timeri);
306+
307+
if (timer->card)
308+
put_device(&timer->card->card_dev);
309+
module_put(timer->module);
310+
mutex_unlock(&register_mutex);
311+
return err;
312+
}
313+
}
314+
299315
list_add_tail(&timeri->open_list, &timer->open_list_head);
300316
snd_timer_check_master(timeri);
301317
mutex_unlock(&register_mutex);
@@ -526,6 +542,10 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
526542
}
527543
}
528544
timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
545+
if (stop)
546+
timeri->flags &= ~SNDRV_TIMER_IFLG_PAUSED;
547+
else
548+
timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
529549
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
530550
SNDRV_TIMER_EVENT_CONTINUE);
531551
unlock:
@@ -587,6 +607,10 @@ int snd_timer_stop(struct snd_timer_instance *timeri)
587607
*/
588608
int snd_timer_continue(struct snd_timer_instance *timeri)
589609
{
610+
/* timer can continue only after pause */
611+
if (!(timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
612+
return -EINVAL;
613+
590614
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
591615
return snd_timer_start_slave(timeri, false);
592616
else
@@ -813,6 +837,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
813837
timer->tmr_subdevice = tid->subdevice;
814838
if (id)
815839
strlcpy(timer->id, id, sizeof(timer->id));
840+
timer->sticks = 1;
816841
INIT_LIST_HEAD(&timer->device_list);
817842
INIT_LIST_HEAD(&timer->open_list_head);
818843
INIT_LIST_HEAD(&timer->active_list_head);
@@ -1817,6 +1842,9 @@ static int snd_timer_user_continue(struct file *file)
18171842
tu = file->private_data;
18181843
if (!tu->timeri)
18191844
return -EBADFD;
1845+
/* start timer instead of continue if it's not used before */
1846+
if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
1847+
return snd_timer_user_start(file);
18201848
tu->timeri->lost = 0;
18211849
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
18221850
}
@@ -1958,6 +1986,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
19581986
tu->qused--;
19591987
spin_unlock_irq(&tu->qlock);
19601988

1989+
mutex_lock(&tu->ioctl_lock);
19611990
if (tu->tread) {
19621991
if (copy_to_user(buffer, &tu->tqueue[qhead],
19631992
sizeof(struct snd_timer_tread)))
@@ -1967,6 +1996,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
19671996
sizeof(struct snd_timer_read)))
19681997
err = -EFAULT;
19691998
}
1999+
mutex_unlock(&tu->ioctl_lock);
19702000

19712001
spin_lock_irq(&tu->qlock);
19722002
if (err < 0)

sound/firewire/fireworks/fireworks.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ struct snd_efw {
108108
u8 *resp_buf;
109109
u8 *pull_ptr;
110110
u8 *push_ptr;
111-
unsigned int resp_queues;
112111
};
113112

114113
int snd_efw_transaction_cmd(struct fw_unit *unit,

sound/firewire/fireworks/fireworks_hwdep.c

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
2525
{
2626
unsigned int length, till_end, type;
2727
struct snd_efw_transaction *t;
28+
u8 *pull_ptr;
2829
long count = 0;
2930

3031
if (remained < sizeof(type) + sizeof(struct snd_efw_transaction))
@@ -38,8 +39,17 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
3839
buf += sizeof(type);
3940

4041
/* write into buffer as many responses as possible */
41-
while (efw->resp_queues > 0) {
42-
t = (struct snd_efw_transaction *)(efw->pull_ptr);
42+
spin_lock_irq(&efw->lock);
43+
44+
/*
45+
* When another task reaches here during this task's access to user
46+
* space, it picks up current position in buffer and can read the same
47+
* series of responses.
48+
*/
49+
pull_ptr = efw->pull_ptr;
50+
51+
while (efw->push_ptr != pull_ptr) {
52+
t = (struct snd_efw_transaction *)(pull_ptr);
4353
length = be32_to_cpu(t->length) * sizeof(__be32);
4454

4555
/* confirm enough space for this response */
@@ -49,41 +59,57 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
4959
/* copy from ring buffer to user buffer */
5060
while (length > 0) {
5161
till_end = snd_efw_resp_buf_size -
52-
(unsigned int)(efw->pull_ptr - efw->resp_buf);
62+
(unsigned int)(pull_ptr - efw->resp_buf);
5363
till_end = min_t(unsigned int, length, till_end);
5464

55-
if (copy_to_user(buf, efw->pull_ptr, till_end))
65+
spin_unlock_irq(&efw->lock);
66+
67+
if (copy_to_user(buf, pull_ptr, till_end))
5668
return -EFAULT;
5769

58-
efw->pull_ptr += till_end;
59-
if (efw->pull_ptr >= efw->resp_buf +
60-
snd_efw_resp_buf_size)
61-
efw->pull_ptr -= snd_efw_resp_buf_size;
70+
spin_lock_irq(&efw->lock);
71+
72+
pull_ptr += till_end;
73+
if (pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
74+
pull_ptr -= snd_efw_resp_buf_size;
6275

6376
length -= till_end;
6477
buf += till_end;
6578
count += till_end;
6679
remained -= till_end;
6780
}
68-
69-
efw->resp_queues--;
7081
}
7182

83+
/*
84+
* All of tasks can read from the buffer nearly simultaneously, but the
85+
* last position for each task is different depending on the length of
86+
* given buffer. Here, for simplicity, a position of buffer is set by
87+
* the latest task. It's better for a listening application to allow one
88+
* thread to read from the buffer. Unless, each task can read different
89+
* sequence of responses depending on variation of buffer length.
90+
*/
91+
efw->pull_ptr = pull_ptr;
92+
93+
spin_unlock_irq(&efw->lock);
94+
7295
return count;
7396
}
7497

7598
static long
7699
hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
77100
loff_t *offset)
78101
{
79-
union snd_firewire_event event;
102+
union snd_firewire_event event = {
103+
.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
104+
};
80105

81-
memset(&event, 0, sizeof(event));
106+
spin_lock_irq(&efw->lock);
82107

83-
event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
84108
event.lock_status.status = (efw->dev_lock_count > 0);
85109
efw->dev_lock_changed = false;
86110

111+
spin_unlock_irq(&efw->lock);
112+
87113
count = min_t(long, count, sizeof(event.lock_status));
88114

89115
if (copy_to_user(buf, &event, count))
@@ -98,26 +124,33 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
98124
{
99125
struct snd_efw *efw = hwdep->private_data;
100126
DEFINE_WAIT(wait);
127+
bool dev_lock_changed;
128+
bool queued;
101129

102130
spin_lock_irq(&efw->lock);
103131

104-
while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) {
132+
dev_lock_changed = efw->dev_lock_changed;
133+
queued = efw->push_ptr != efw->pull_ptr;
134+
135+
while (!dev_lock_changed && !queued) {
105136
prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
106137
spin_unlock_irq(&efw->lock);
107138
schedule();
108139
finish_wait(&efw->hwdep_wait, &wait);
109140
if (signal_pending(current))
110141
return -ERESTARTSYS;
111142
spin_lock_irq(&efw->lock);
143+
dev_lock_changed = efw->dev_lock_changed;
144+
queued = efw->push_ptr != efw->pull_ptr;
112145
}
113146

114-
if (efw->dev_lock_changed)
147+
spin_unlock_irq(&efw->lock);
148+
149+
if (dev_lock_changed)
115150
count = hwdep_read_locked(efw, buf, count, offset);
116-
else if (efw->resp_queues > 0)
151+
else if (queued)
117152
count = hwdep_read_resp_buf(efw, buf, count, offset);
118153

119-
spin_unlock_irq(&efw->lock);
120-
121154
return count;
122155
}
123156

@@ -160,7 +193,7 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
160193
poll_wait(file, &efw->hwdep_wait, wait);
161194

162195
spin_lock_irq(&efw->lock);
163-
if (efw->dev_lock_changed || (efw->resp_queues > 0))
196+
if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr)
164197
events = POLLIN | POLLRDNORM;
165198
else
166199
events = 0;

sound/firewire/fireworks/fireworks_proc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ proc_read_queues_state(struct snd_info_entry *entry,
188188
else
189189
consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr);
190190

191-
snd_iprintf(buffer, "%d %d/%d\n",
192-
efw->resp_queues, consumed, snd_efw_resp_buf_size);
191+
snd_iprintf(buffer, "%d/%d\n",
192+
consumed, snd_efw_resp_buf_size);
193193
}
194194

195195
static void

sound/firewire/fireworks/fireworks_transaction.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
121121
size_t capacity, till_end;
122122
struct snd_efw_transaction *t;
123123

124-
spin_lock_irq(&efw->lock);
125-
126124
t = (struct snd_efw_transaction *)data;
127125
length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
128126

127+
spin_lock_irq(&efw->lock);
128+
129129
if (efw->push_ptr < efw->pull_ptr)
130130
capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
131131
else
@@ -155,7 +155,6 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
155155
}
156156

157157
/* for hwdep */
158-
efw->resp_queues++;
159158
wake_up(&efw->hwdep_wait);
160159

161160
*rcode = RCODE_COMPLETE;

sound/firewire/tascam/tascam-hwdep.c

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,14 @@
1616

1717
#include "tascam.h"
1818

19-
static long hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
20-
long count)
21-
{
22-
union snd_firewire_event event;
23-
24-
memset(&event, 0, sizeof(event));
25-
26-
event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
27-
event.lock_status.status = (tscm->dev_lock_count > 0);
28-
tscm->dev_lock_changed = false;
29-
30-
count = min_t(long, count, sizeof(event.lock_status));
31-
32-
if (copy_to_user(buf, &event, count))
33-
return -EFAULT;
34-
35-
return count;
36-
}
37-
3819
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
3920
loff_t *offset)
4021
{
4122
struct snd_tscm *tscm = hwdep->private_data;
4223
DEFINE_WAIT(wait);
43-
union snd_firewire_event event;
24+
union snd_firewire_event event = {
25+
.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
26+
};
4427

4528
spin_lock_irq(&tscm->lock);
4629

@@ -54,10 +37,16 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
5437
spin_lock_irq(&tscm->lock);
5538
}
5639

57-
memset(&event, 0, sizeof(event));
58-
count = hwdep_read_locked(tscm, buf, count);
40+
event.lock_status.status = (tscm->dev_lock_count > 0);
41+
tscm->dev_lock_changed = false;
42+
5943
spin_unlock_irq(&tscm->lock);
6044

45+
count = min_t(long, count, sizeof(event.lock_status));
46+
47+
if (copy_to_user(buf, &event, count))
48+
return -EFAULT;
49+
6150
return count;
6251
}
6352

0 commit comments

Comments
 (0)