Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: fireface: fix locking bug in ff400_copy_msg_to_user()

The ff400_copy_msg_to_user() function drops the spin lock to call
copy_to_user(). However, if the copy_to_user() fails, then it must
take the lock again before returning. Failure to take the lock leads
to a double unlock in the caller, hwdep_read().

Fixes: acdebd8b4c0c ("ALSA: fireface: implement message parser for Fireface 400")
Signed-off-by: Dan Carpenter <error27@gmail.com>
Acked-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/Y8at+W/7OGvEBY8O@kili
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Dan Carpenter and committed by
Takashi Iwai
81c254a6 3ee0fe7f

+8 -6
+8 -6
sound/firewire/fireface/ff-protocol-former.c
··· 680 680 struct ff400_msg_parser *parser = ff->msg_parser; 681 681 u32 type = SNDRV_FIREWIRE_EVENT_FF400_MESSAGE; 682 682 long consumed = 0; 683 + int ret = 0; 683 684 684 685 if (count < 8) 685 686 return 0; 686 687 687 688 spin_unlock_irq(&ff->lock); 688 - 689 689 if (copy_to_user(buf, &type, sizeof(type))) 690 - return -EFAULT; 691 - 690 + ret = -EFAULT; 692 691 spin_lock_irq(&ff->lock); 692 + if (ret) 693 + return ret; 693 694 694 695 count -= sizeof(type); 695 696 consumed += sizeof(type); 696 697 697 698 while (count >= sizeof(*parser->msgs) && parser->pull_pos != parser->push_pos) { 698 699 spin_unlock_irq(&ff->lock); 699 - 700 700 if (copy_to_user(buf + consumed, parser->msgs + parser->pull_pos, 701 701 sizeof(*parser->msgs))) 702 - return -EFAULT; 703 - 702 + ret = -EFAULT; 704 703 spin_lock_irq(&ff->lock); 704 + if (ret) 705 + return ret; 706 + 705 707 ++parser->pull_pos; 706 708 if (parser->pull_pos >= FF400_QUEUE_SIZE) 707 709 parser->pull_pos = 0;