Skip to content

Commit

Permalink
Merge tag 'sound-4.14-rc5' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "It's been a busy week for defending the attacks from fuzzer people.

  This contains various USB-audio driver fixes and sequencer core fixes
  spotted by syzkaller and other fuzzer, as well as one quirk for a
  Plantronics USB audio device"

* tag 'sound-4.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: caiaq: Fix stray URB at probe error path
  ALSA: seq: Fix use-after-free at creating a port
  ALSA: usb-audio: Kill stray URB at exiting
  ALSA: line6: Fix leftover URB at error-path during probe
  ALSA: line6: Fix NULL dereference at podhd_disconnect()
  ALSA: line6: Fix missing initialization before error path
  ALSA: seq: Fix copy_from_user() call inside lock
  ALSA: usb-audio: Add sample rate quirk for Plantronics P610
  • Loading branch information
Linus Torvalds committed Oct 12, 2017
2 parents 467251c + 99fee50 commit 7702f47
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 22 deletions.
1 change: 1 addition & 0 deletions include/sound/seq_virmidi.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct snd_virmidi_dev {
int port; /* created/attached port */
unsigned int flags; /* SNDRV_VIRMIDI_* */
rwlock_t filelist_lock;
struct rw_semaphore filelist_sem;
struct list_head filelist;
};

Expand Down
6 changes: 5 additions & 1 deletion sound/core/seq/seq_clientmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
struct snd_seq_port_info *info = arg;
struct snd_seq_client_port *port;
struct snd_seq_port_callback *callback;
int port_idx;

/* it is not allowed to create the port for an another client */
if (info->addr.client != client->number)
Expand All @@ -1269,7 +1270,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
return -ENOMEM;

if (client->type == USER_CLIENT && info->kernel) {
snd_seq_delete_port(client, port->addr.port);
port_idx = port->addr.port;
snd_seq_port_unlock(port);
snd_seq_delete_port(client, port_idx);
return -EINVAL;
}
if (client->type == KERNEL_CLIENT) {
Expand All @@ -1290,6 +1293,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)

snd_seq_set_port_info(port, info);
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
snd_seq_port_unlock(port);

return 0;
}
Expand Down
7 changes: 5 additions & 2 deletions sound/core/seq/seq_ports.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
}


/* create a port, port number is returned (-1 on failure) */
/* create a port, port number is returned (-1 on failure);
* the caller needs to unref the port via snd_seq_port_unlock() appropriately
*/
struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
int port)
{
Expand Down Expand Up @@ -151,6 +153,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
snd_use_lock_init(&new_port->use_lock);
port_subs_info_init(&new_port->c_src);
port_subs_info_init(&new_port->c_dest);
snd_use_lock_use(&new_port->use_lock);

num = port >= 0 ? port : 0;
mutex_lock(&client->ports_mutex);
Expand All @@ -165,9 +168,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
list_add_tail(&new_port->list, &p->list);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
write_unlock_irqrestore(&client->ports_lock, flags);
mutex_unlock(&client->ports_mutex);
sprintf(new_port->name, "port-%d", num);

return new_port;
}
Expand Down
27 changes: 19 additions & 8 deletions sound/core/seq/seq_virmidi.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,17 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
* decode input event and put to read buffer of each opened file
*/
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
struct snd_seq_event *ev)
struct snd_seq_event *ev,
bool atomic)
{
struct snd_virmidi *vmidi;
unsigned char msg[4];
int len;

read_lock(&rdev->filelist_lock);
if (atomic)
read_lock(&rdev->filelist_lock);
else
down_read(&rdev->filelist_sem);
list_for_each_entry(vmidi, &rdev->filelist, list) {
if (!vmidi->trigger)
continue;
Expand All @@ -97,7 +101,10 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
snd_rawmidi_receive(vmidi->substream, msg, len);
}
}
read_unlock(&rdev->filelist_lock);
if (atomic)
read_unlock(&rdev->filelist_lock);
else
up_read(&rdev->filelist_sem);

return 0;
}
Expand All @@ -115,7 +122,7 @@ int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev)
struct snd_virmidi_dev *rdev;

rdev = rmidi->private_data;
return snd_virmidi_dev_receive_event(rdev, ev);
return snd_virmidi_dev_receive_event(rdev, ev, true);
}
#endif /* 0 */

Expand All @@ -130,7 +137,7 @@ static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
rdev = private_data;
if (!(rdev->flags & SNDRV_VIRMIDI_USE))
return 0; /* ignored */
return snd_virmidi_dev_receive_event(rdev, ev);
return snd_virmidi_dev_receive_event(rdev, ev, atomic);
}

/*
Expand Down Expand Up @@ -209,7 +216,6 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
struct snd_rawmidi_runtime *runtime = substream->runtime;
struct snd_virmidi *vmidi;
unsigned long flags;

vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
if (vmidi == NULL)
Expand All @@ -223,9 +229,11 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
vmidi->client = rdev->client;
vmidi->port = rdev->port;
runtime->private_data = vmidi;
write_lock_irqsave(&rdev->filelist_lock, flags);
down_write(&rdev->filelist_sem);
write_lock_irq(&rdev->filelist_lock);
list_add_tail(&vmidi->list, &rdev->filelist);
write_unlock_irqrestore(&rdev->filelist_lock, flags);
write_unlock_irq(&rdev->filelist_lock);
up_write(&rdev->filelist_sem);
vmidi->rdev = rdev;
return 0;
}
Expand Down Expand Up @@ -264,9 +272,11 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
struct snd_virmidi *vmidi = substream->runtime->private_data;

down_write(&rdev->filelist_sem);
write_lock_irq(&rdev->filelist_lock);
list_del(&vmidi->list);
write_unlock_irq(&rdev->filelist_lock);
up_write(&rdev->filelist_sem);
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
Expand Down Expand Up @@ -520,6 +530,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
rdev->rmidi = rmidi;
rdev->device = device;
rdev->client = -1;
init_rwsem(&rdev->filelist_sem);
rwlock_init(&rdev->filelist_lock);
INIT_LIST_HEAD(&rdev->filelist);
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
Expand Down
12 changes: 9 additions & 3 deletions sound/usb/caiaq/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,12 @@ static int init_card(struct snd_usb_caiaqdev *cdev)

err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
if (err)
return err;
goto err_kill_urb;

if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ))
return -ENODEV;
if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ)) {
err = -ENODEV;
goto err_kill_urb;
}

usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
cdev->vendor_name, CAIAQ_USB_STR_LEN);
Expand Down Expand Up @@ -507,6 +509,10 @@ static int init_card(struct snd_usb_caiaqdev *cdev)

setup_card(cdev);
return 0;

err_kill_urb:
usb_kill_urb(&cdev->ep1_in_urb);
return err;
}

static int snd_probe(struct usb_interface *intf,
Expand Down
7 changes: 4 additions & 3 deletions sound/usb/line6/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,9 +779,10 @@ int line6_probe(struct usb_interface *interface,
return 0;

error:
if (line6->disconnect)
line6->disconnect(line6);
snd_card_free(card);
/* we can call disconnect callback here because no close-sync is
* needed yet at this point
*/
line6_disconnect(interface);
return ret;
}
EXPORT_SYMBOL_GPL(line6_probe);
Expand Down
8 changes: 5 additions & 3 deletions sound/usb/line6/podhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ static void podhd_disconnect(struct usb_line6 *line6)

intf = usb_ifnum_to_if(line6->usbdev,
pod->line6.properties->ctrl_if);
usb_driver_release_interface(&podhd_driver, intf);
if (intf)
usb_driver_release_interface(&podhd_driver, intf);
}
}

Expand All @@ -317,6 +318,9 @@ static int podhd_init(struct usb_line6 *line6,

line6->disconnect = podhd_disconnect;

init_timer(&pod->startup_timer);
INIT_WORK(&pod->startup_work, podhd_startup_workqueue);

if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
/* claim the data interface */
intf = usb_ifnum_to_if(line6->usbdev,
Expand Down Expand Up @@ -358,8 +362,6 @@ static int podhd_init(struct usb_line6 *line6,
}

/* init device and delay registering */
init_timer(&pod->startup_timer);
INIT_WORK(&pod->startup_work, podhd_startup_workqueue);
podhd_startup(pod);
return 0;
}
Expand Down
12 changes: 10 additions & 2 deletions sound/usb/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,9 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)

static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
{
/* kill pending URBs */
snd_usb_mixer_disconnect(mixer);

kfree(mixer->id_elems);
if (mixer->urb) {
kfree(mixer->urb->transfer_buffer);
Expand Down Expand Up @@ -2584,8 +2587,13 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,

void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer)
{
usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb);
if (mixer->disconnected)
return;
if (mixer->urb)
usb_kill_urb(mixer->urb);
if (mixer->rc_urb)
usb_kill_urb(mixer->rc_urb);
mixer->disconnected = true;
}

#ifdef CONFIG_PM
Expand Down
2 changes: 2 additions & 0 deletions sound/usb/mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ struct usb_mixer_interface {
struct urb *rc_urb;
struct usb_ctrlrequest *rc_setup_packet;
u8 rc_buffer[6];

bool disconnected;
};

#define MAX_CHANNELS 16 /* max logical channels */
Expand Down
1 change: 1 addition & 0 deletions sound/usb/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */
case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
case USB_ID(0x047F, 0xC022): /* Plantronics C310 */
case USB_ID(0x047F, 0xC02F): /* Plantronics P610 */
case USB_ID(0x047F, 0xC036): /* Plantronics C520-M */
case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
Expand Down

0 comments on commit 7702f47

Please sign in to comment.