aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/timer.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-11-05 04:07:43 -0500
committerTakashi Iwai <tiwai@suse.de>2017-11-06 04:41:24 -0500
commit9b7d869ee5a77ed4a462372bb89af622e705bfb8 (patch)
tree8151b57ebb526eac4c1bf711aa01bfe0972eecaa /sound/core/timer.c
parentf5ce817951f38023588b2b8308beca79abe20507 (diff)
ALSA: timer: Limit max instances per timer
Currently we allow unlimited number of timer instances, and it may bring the system hogging way too much CPU when too many timer instances are opened and processed concurrently. This may end up with a soft-lockup report as triggered by syzkaller, especially when hrtimer backend is deployed. Since such insane number of instances aren't demanded by the normal use case of ALSA sequencer and it merely opens a risk only for abuse, this patch introduces the upper limit for the number of instances per timer backend. As default, it's set to 1000, but for the fine-grained timer like hrtimer, it's set to 100. Reported-by: syzbot Tested-by: Jérôme Glisse <jglisse@redhat.com> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r--sound/core/timer.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 6cdd04a45962..15e82a656d96 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -180,7 +180,7 @@ static void snd_timer_request(struct snd_timer_id *tid)
180 * 180 *
181 * call this with register_mutex down. 181 * call this with register_mutex down.
182 */ 182 */
183static void snd_timer_check_slave(struct snd_timer_instance *slave) 183static int snd_timer_check_slave(struct snd_timer_instance *slave)
184{ 184{
185 struct snd_timer *timer; 185 struct snd_timer *timer;
186 struct snd_timer_instance *master; 186 struct snd_timer_instance *master;
@@ -190,16 +190,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
190 list_for_each_entry(master, &timer->open_list_head, open_list) { 190 list_for_each_entry(master, &timer->open_list_head, open_list) {
191 if (slave->slave_class == master->slave_class && 191 if (slave->slave_class == master->slave_class &&
192 slave->slave_id == master->slave_id) { 192 slave->slave_id == master->slave_id) {
193 if (master->timer->num_instances >=
194 master->timer->max_instances)
195 return -EBUSY;
193 list_move_tail(&slave->open_list, 196 list_move_tail(&slave->open_list,
194 &master->slave_list_head); 197 &master->slave_list_head);
198 master->timer->num_instances++;
195 spin_lock_irq(&slave_active_lock); 199 spin_lock_irq(&slave_active_lock);
196 slave->master = master; 200 slave->master = master;
197 slave->timer = master->timer; 201 slave->timer = master->timer;
198 spin_unlock_irq(&slave_active_lock); 202 spin_unlock_irq(&slave_active_lock);
199 return; 203 return 0;
200 } 204 }
201 } 205 }
202 } 206 }
207 return 0;
203} 208}
204 209
205/* 210/*
@@ -208,7 +213,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
208 * 213 *
209 * call this with register_mutex down. 214 * call this with register_mutex down.
210 */ 215 */
211static void snd_timer_check_master(struct snd_timer_instance *master) 216static int snd_timer_check_master(struct snd_timer_instance *master)
212{ 217{
213 struct snd_timer_instance *slave, *tmp; 218 struct snd_timer_instance *slave, *tmp;
214 219
@@ -216,7 +221,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
216 list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { 221 list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
217 if (slave->slave_class == master->slave_class && 222 if (slave->slave_class == master->slave_class &&
218 slave->slave_id == master->slave_id) { 223 slave->slave_id == master->slave_id) {
224 if (master->timer->num_instances >=
225 master->timer->max_instances)
226 return -EBUSY;
219 list_move_tail(&slave->open_list, &master->slave_list_head); 227 list_move_tail(&slave->open_list, &master->slave_list_head);
228 master->timer->num_instances++;
220 spin_lock_irq(&slave_active_lock); 229 spin_lock_irq(&slave_active_lock);
221 spin_lock(&master->timer->lock); 230 spin_lock(&master->timer->lock);
222 slave->master = master; 231 slave->master = master;
@@ -228,8 +237,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
228 spin_unlock_irq(&slave_active_lock); 237 spin_unlock_irq(&slave_active_lock);
229 } 238 }
230 } 239 }
240 return 0;
231} 241}
232 242
243static int snd_timer_close_locked(struct snd_timer_instance *timeri);
244
233/* 245/*
234 * open a timer instance 246 * open a timer instance
235 * when opening a master, the slave id must be here given. 247 * when opening a master, the slave id must be here given.
@@ -240,6 +252,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
240{ 252{
241 struct snd_timer *timer; 253 struct snd_timer *timer;
242 struct snd_timer_instance *timeri = NULL; 254 struct snd_timer_instance *timeri = NULL;
255 int err;
243 256
244 if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { 257 if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
245 /* open a slave instance */ 258 /* open a slave instance */
@@ -259,10 +272,14 @@ int snd_timer_open(struct snd_timer_instance **ti,
259 timeri->slave_id = tid->device; 272 timeri->slave_id = tid->device;
260 timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; 273 timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
261 list_add_tail(&timeri->open_list, &snd_timer_slave_list); 274 list_add_tail(&timeri->open_list, &snd_timer_slave_list);
262 snd_timer_check_slave(timeri); 275 err = snd_timer_check_slave(timeri);
276 if (err < 0) {
277 snd_timer_close_locked(timeri);
278 timeri = NULL;
279 }
263 mutex_unlock(&register_mutex); 280 mutex_unlock(&register_mutex);
264 *ti = timeri; 281 *ti = timeri;
265 return 0; 282 return err;
266 } 283 }
267 284
268 /* open a master instance */ 285 /* open a master instance */
@@ -288,6 +305,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
288 return -EBUSY; 305 return -EBUSY;
289 } 306 }
290 } 307 }
308 if (timer->num_instances >= timer->max_instances) {
309 mutex_unlock(&register_mutex);
310 return -EBUSY;
311 }
291 timeri = snd_timer_instance_new(owner, timer); 312 timeri = snd_timer_instance_new(owner, timer);
292 if (!timeri) { 313 if (!timeri) {
293 mutex_unlock(&register_mutex); 314 mutex_unlock(&register_mutex);
@@ -314,25 +335,27 @@ int snd_timer_open(struct snd_timer_instance **ti,
314 } 335 }
315 336
316 list_add_tail(&timeri->open_list, &timer->open_list_head); 337 list_add_tail(&timeri->open_list, &timer->open_list_head);
317 snd_timer_check_master(timeri); 338 timer->num_instances++;
339 err = snd_timer_check_master(timeri);
340 if (err < 0) {
341 snd_timer_close_locked(timeri);
342 timeri = NULL;
343 }
318 mutex_unlock(&register_mutex); 344 mutex_unlock(&register_mutex);
319 *ti = timeri; 345 *ti = timeri;
320 return 0; 346 return err;
321} 347}
322EXPORT_SYMBOL(snd_timer_open); 348EXPORT_SYMBOL(snd_timer_open);
323 349
324/* 350/*
325 * close a timer instance 351 * close a timer instance
352 * call this with register_mutex down.
326 */ 353 */
327int snd_timer_close(struct snd_timer_instance *timeri) 354static int snd_timer_close_locked(struct snd_timer_instance *timeri)
328{ 355{
329 struct snd_timer *timer = NULL; 356 struct snd_timer *timer = NULL;
330 struct snd_timer_instance *slave, *tmp; 357 struct snd_timer_instance *slave, *tmp;
331 358
332 if (snd_BUG_ON(!timeri))
333 return -ENXIO;
334
335 mutex_lock(&register_mutex);
336 list_del(&timeri->open_list); 359 list_del(&timeri->open_list);
337 360
338 /* force to stop the timer */ 361 /* force to stop the timer */
@@ -340,6 +363,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
340 363
341 timer = timeri->timer; 364 timer = timeri->timer;
342 if (timer) { 365 if (timer) {
366 timer->num_instances--;
343 /* wait, until the active callback is finished */ 367 /* wait, until the active callback is finished */
344 spin_lock_irq(&timer->lock); 368 spin_lock_irq(&timer->lock);
345 while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { 369 while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -355,6 +379,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
355 list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, 379 list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
356 open_list) { 380 open_list) {
357 list_move_tail(&slave->open_list, &snd_timer_slave_list); 381 list_move_tail(&slave->open_list, &snd_timer_slave_list);
382 timer->num_instances--;
358 slave->master = NULL; 383 slave->master = NULL;
359 slave->timer = NULL; 384 slave->timer = NULL;
360 list_del_init(&slave->ack_list); 385 list_del_init(&slave->ack_list);
@@ -382,9 +407,24 @@ int snd_timer_close(struct snd_timer_instance *timeri)
382 module_put(timer->module); 407 module_put(timer->module);
383 } 408 }
384 409
385 mutex_unlock(&register_mutex);
386 return 0; 410 return 0;
387} 411}
412
413/*
414 * close a timer instance
415 */
416int snd_timer_close(struct snd_timer_instance *timeri)
417{
418 int err;
419
420 if (snd_BUG_ON(!timeri))
421 return -ENXIO;
422
423 mutex_lock(&register_mutex);
424 err = snd_timer_close_locked(timeri);
425 mutex_unlock(&register_mutex);
426 return err;
427}
388EXPORT_SYMBOL(snd_timer_close); 428EXPORT_SYMBOL(snd_timer_close);
389 429
390unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) 430unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
@@ -856,6 +896,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
856 spin_lock_init(&timer->lock); 896 spin_lock_init(&timer->lock);
857 tasklet_init(&timer->task_queue, snd_timer_tasklet, 897 tasklet_init(&timer->task_queue, snd_timer_tasklet,
858 (unsigned long)timer); 898 (unsigned long)timer);
899 timer->max_instances = 1000; /* default limit per timer */
859 if (card != NULL) { 900 if (card != NULL) {
860 timer->module = card->module; 901 timer->module = card->module;
861 err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); 902 err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);