Commit 4cd664c0 authored by Takashi Iwai's avatar Takashi Iwai Committed by Greg Kroah-Hartman

ALSA: seq: Fix race of get-subscription call vs port-delete ioctls

[ Upstream commit 2eabc5ec ]

The snd_seq_ioctl_get_subscription() retrieves the port subscriber
information as a pointer, while the object isn't protected, hence it
may be deleted before the actual reference.  This race was spotted by
syzkaller and may lead to a UAF.

The fix is simply copying the data in the lookup function that
performs in the rwsem to protect against the deletion.

Reported-by: syzbot+9437020c82413d00222d@syzkaller.appspotmail.com
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent d4cd46f2
...@@ -1900,20 +1900,14 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, ...@@ -1900,20 +1900,14 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
int result; int result;
struct snd_seq_client *sender = NULL; struct snd_seq_client *sender = NULL;
struct snd_seq_client_port *sport = NULL; struct snd_seq_client_port *sport = NULL;
struct snd_seq_subscribers *p;
result = -EINVAL; result = -EINVAL;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
goto __end; goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
goto __end; goto __end;
p = snd_seq_port_get_subscription(&sport->c_src, &subs->dest); result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
if (p) { subs);
result = 0;
*subs = p->info;
} else
result = -ENOENT;
__end: __end:
if (sport) if (sport)
snd_seq_port_unlock(sport); snd_seq_port_unlock(sport);
......
...@@ -635,20 +635,23 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, ...@@ -635,20 +635,23 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
/* get matched subscriber */ /* get matched subscriber */
struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr) struct snd_seq_addr *dest_addr,
struct snd_seq_port_subscribe *subs)
{ {
struct snd_seq_subscribers *s, *found = NULL; struct snd_seq_subscribers *s;
int err = -ENOENT;
down_read(&src_grp->list_mutex); down_read(&src_grp->list_mutex);
list_for_each_entry(s, &src_grp->list_head, src_list) { list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) { if (addr_match(dest_addr, &s->info.dest)) {
found = s; *subs = s->info;
err = 0;
break; break;
} }
} }
up_read(&src_grp->list_mutex); up_read(&src_grp->list_mutex);
return found; return err;
} }
/* /*
......
...@@ -135,7 +135,8 @@ int snd_seq_port_subscribe(struct snd_seq_client_port *port, ...@@ -135,7 +135,8 @@ int snd_seq_port_subscribe(struct snd_seq_client_port *port,
struct snd_seq_port_subscribe *info); struct snd_seq_port_subscribe *info);
/* get matched subscriber */ /* get matched subscriber */
struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr); struct snd_seq_addr *dest_addr,
struct snd_seq_port_subscribe *subs);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment