]>
Commit | Line | Data |
---|---|---|
1cd4ef76 SL |
1 | From 97f213d5b8850731c3bb1cd42c27a229748c8057 Mon Sep 17 00:00:00 2001 |
2 | From: Takashi Iwai <tiwai@suse.de> | |
3 | Date: Tue, 9 Apr 2019 18:04:17 +0200 | |
4 | Subject: ALSA: seq: Fix race of get-subscription call vs port-delete ioctls | |
5 | ||
6 | [ Upstream commit 2eabc5ec8ab4d4748a82050dfcb994119b983750 ] | |
7 | ||
8 | The snd_seq_ioctl_get_subscription() retrieves the port subscriber | |
9 | information as a pointer, while the object isn't protected, hence it | |
10 | may be deleted before the actual reference. This race was spotted by | |
11 | syzkaller and may lead to a UAF. | |
12 | ||
13 | The fix is simply copying the data in the lookup function that | |
14 | performs in the rwsem to protect against the deletion. | |
15 | ||
16 | Reported-by: syzbot+9437020c82413d00222d@syzkaller.appspotmail.com | |
17 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
18 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
19 | --- | |
20 | sound/core/seq/seq_clientmgr.c | 10 ++-------- | |
21 | sound/core/seq/seq_ports.c | 13 ++++++++----- | |
22 | sound/core/seq/seq_ports.h | 5 +++-- | |
23 | 3 files changed, 13 insertions(+), 15 deletions(-) | |
24 | ||
25 | diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c | |
26 | index 692631bd4a35..068880ac47b5 100644 | |
27 | --- a/sound/core/seq/seq_clientmgr.c | |
28 | +++ b/sound/core/seq/seq_clientmgr.c | |
29 | @@ -1904,20 +1904,14 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, | |
30 | int result; | |
31 | struct snd_seq_client *sender = NULL; | |
32 | struct snd_seq_client_port *sport = NULL; | |
33 | - struct snd_seq_subscribers *p; | |
34 | ||
35 | result = -EINVAL; | |
36 | if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) | |
37 | goto __end; | |
38 | if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) | |
39 | goto __end; | |
40 | - p = snd_seq_port_get_subscription(&sport->c_src, &subs->dest); | |
41 | - if (p) { | |
42 | - result = 0; | |
43 | - *subs = p->info; | |
44 | - } else | |
45 | - result = -ENOENT; | |
46 | - | |
47 | + result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest, | |
48 | + subs); | |
49 | __end: | |
50 | if (sport) | |
51 | snd_seq_port_unlock(sport); | |
52 | diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c | |
53 | index d3fc73ac230b..c8fa4336bccd 100644 | |
54 | --- a/sound/core/seq/seq_ports.c | |
55 | +++ b/sound/core/seq/seq_ports.c | |
56 | @@ -635,20 +635,23 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, | |
57 | ||
58 | ||
59 | /* get matched subscriber */ | |
60 | -struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, | |
61 | - struct snd_seq_addr *dest_addr) | |
62 | +int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, | |
63 | + struct snd_seq_addr *dest_addr, | |
64 | + struct snd_seq_port_subscribe *subs) | |
65 | { | |
66 | - struct snd_seq_subscribers *s, *found = NULL; | |
67 | + struct snd_seq_subscribers *s; | |
68 | + int err = -ENOENT; | |
69 | ||
70 | down_read(&src_grp->list_mutex); | |
71 | list_for_each_entry(s, &src_grp->list_head, src_list) { | |
72 | if (addr_match(dest_addr, &s->info.dest)) { | |
73 | - found = s; | |
74 | + *subs = s->info; | |
75 | + err = 0; | |
76 | break; | |
77 | } | |
78 | } | |
79 | up_read(&src_grp->list_mutex); | |
80 | - return found; | |
81 | + return err; | |
82 | } | |
83 | ||
84 | /* | |
85 | diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h | |
86 | index 26bd71f36c41..06003b36652e 100644 | |
87 | --- a/sound/core/seq/seq_ports.h | |
88 | +++ b/sound/core/seq/seq_ports.h | |
89 | @@ -135,7 +135,8 @@ int snd_seq_port_subscribe(struct snd_seq_client_port *port, | |
90 | struct snd_seq_port_subscribe *info); | |
91 | ||
92 | /* get matched subscriber */ | |
93 | -struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, | |
94 | - struct snd_seq_addr *dest_addr); | |
95 | +int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, | |
96 | + struct snd_seq_addr *dest_addr, | |
97 | + struct snd_seq_port_subscribe *subs); | |
98 | ||
99 | #endif | |
100 | -- | |
101 | 2.20.1 | |
102 |