Skip to content

Commit c9ce148

Browse files
committed
ALSA: seq: Avoid module auto-load handling at event delivery
snd_seq_client_use_ptr() is supposed to return the snd_seq_client object for the given client ID, and it tries to handle the module auto-loading when no matching object is found. Although the module handling is performed only conditionally with "!in_interrupt()", this condition may be fragile, e.g. when the code is called from the ALSA timer callback where the spinlock is temporarily disabled while the irq is disabled. Then his doesn't fit well and spews the error about sleep from invalid context, as complained recently by syzbot. Also, in general, handling the module-loading at each time if no matching object is found is really an overkill. It can be still useful when performed at the top-level ioctl or proc reads, but it shouldn't be done at event delivery at all. For addressing the issues above, this patch disables the module handling in snd_seq_client_use_ptr() in normal cases like event deliveries, but allow only in limited and safe situations. A new function client_load_and_use_ptr() is used for the cases where the module loading can be done safely, instead. Reported-by: syzbot+4cb9fad083898f54c517@syzkaller.appspotmail.com Closes: https://lore.kernel.org/67c272e5.050a0220.dc10f.0159.GAE@google.com Cc: <stable@vger.kernel.org> Link: https://patch.msgid.link/20250301114530.8975-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent f479ecc commit c9ce148

File tree

1 file changed

+30
-16
lines changed

1 file changed

+30
-16
lines changed

sound/core/seq/seq_clientmgr.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ static struct snd_seq_client *clientptr(int clientid)
106106
return clienttab[clientid];
107107
}
108108

109-
struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
109+
static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
110110
{
111111
unsigned long flags;
112112
struct snd_seq_client *client;
@@ -126,7 +126,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
126126
}
127127
spin_unlock_irqrestore(&clients_lock, flags);
128128
#ifdef CONFIG_MODULES
129-
if (!in_interrupt()) {
129+
if (load_module) {
130130
static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS);
131131
static DECLARE_BITMAP(card_requested, SNDRV_CARDS);
132132

@@ -168,6 +168,20 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
168168
return client;
169169
}
170170

171+
/* get snd_seq_client object for the given id quickly */
172+
struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
173+
{
174+
return client_use_ptr(clientid, false);
175+
}
176+
177+
/* get snd_seq_client object for the given id;
178+
* if not found, retry after loading the modules
179+
*/
180+
static struct snd_seq_client *client_load_and_use_ptr(int clientid)
181+
{
182+
return client_use_ptr(clientid, IS_ENABLED(CONFIG_MODULES));
183+
}
184+
171185
/* Take refcount and perform ioctl_mutex lock on the given client;
172186
* used only for OSS sequencer
173187
* Unlock via snd_seq_client_ioctl_unlock() below
@@ -176,7 +190,7 @@ bool snd_seq_client_ioctl_lock(int clientid)
176190
{
177191
struct snd_seq_client *client;
178192

179-
client = snd_seq_client_use_ptr(clientid);
193+
client = client_load_and_use_ptr(clientid);
180194
if (!client)
181195
return false;
182196
mutex_lock(&client->ioctl_mutex);
@@ -1195,7 +1209,7 @@ static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg)
11951209
int err = 0;
11961210

11971211
/* requested client number */
1198-
cptr = snd_seq_client_use_ptr(info->client);
1212+
cptr = client_load_and_use_ptr(info->client);
11991213
if (cptr == NULL)
12001214
return -ENOENT; /* don't change !!! */
12011215

@@ -1257,7 +1271,7 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
12571271
struct snd_seq_client *cptr;
12581272

12591273
/* requested client number */
1260-
cptr = snd_seq_client_use_ptr(client_info->client);
1274+
cptr = client_load_and_use_ptr(client_info->client);
12611275
if (cptr == NULL)
12621276
return -ENOENT; /* don't change !!! */
12631277

@@ -1396,7 +1410,7 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
13961410
struct snd_seq_client *cptr;
13971411
struct snd_seq_client_port *port;
13981412

1399-
cptr = snd_seq_client_use_ptr(info->addr.client);
1413+
cptr = client_load_and_use_ptr(info->addr.client);
14001414
if (cptr == NULL)
14011415
return -ENXIO;
14021416

@@ -1503,10 +1517,10 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
15031517
struct snd_seq_client *receiver = NULL, *sender = NULL;
15041518
struct snd_seq_client_port *sport = NULL, *dport = NULL;
15051519

1506-
receiver = snd_seq_client_use_ptr(subs->dest.client);
1520+
receiver = client_load_and_use_ptr(subs->dest.client);
15071521
if (!receiver)
15081522
goto __end;
1509-
sender = snd_seq_client_use_ptr(subs->sender.client);
1523+
sender = client_load_and_use_ptr(subs->sender.client);
15101524
if (!sender)
15111525
goto __end;
15121526
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
@@ -1871,7 +1885,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
18711885
struct snd_seq_client_pool *info = arg;
18721886
struct snd_seq_client *cptr;
18731887

1874-
cptr = snd_seq_client_use_ptr(info->client);
1888+
cptr = client_load_and_use_ptr(info->client);
18751889
if (cptr == NULL)
18761890
return -ENOENT;
18771891
memset(info, 0, sizeof(*info));
@@ -1975,7 +1989,7 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
19751989
struct snd_seq_client_port *sport = NULL;
19761990

19771991
result = -EINVAL;
1978-
sender = snd_seq_client_use_ptr(subs->sender.client);
1992+
sender = client_load_and_use_ptr(subs->sender.client);
19791993
if (!sender)
19801994
goto __end;
19811995
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
@@ -2006,7 +2020,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
20062020
struct list_head *p;
20072021
int i;
20082022

2009-
cptr = snd_seq_client_use_ptr(subs->root.client);
2023+
cptr = client_load_and_use_ptr(subs->root.client);
20102024
if (!cptr)
20112025
goto __end;
20122026
port = snd_seq_port_use_ptr(cptr, subs->root.port);
@@ -2073,7 +2087,7 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
20732087
if (info->client < 0)
20742088
info->client = 0;
20752089
for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) {
2076-
cptr = snd_seq_client_use_ptr(info->client);
2090+
cptr = client_load_and_use_ptr(info->client);
20772091
if (cptr)
20782092
break; /* found */
20792093
}
@@ -2096,7 +2110,7 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
20962110
struct snd_seq_client *cptr;
20972111
struct snd_seq_client_port *port = NULL;
20982112

2099-
cptr = snd_seq_client_use_ptr(info->addr.client);
2113+
cptr = client_load_and_use_ptr(info->addr.client);
21002114
if (cptr == NULL)
21012115
return -ENXIO;
21022116

@@ -2193,7 +2207,7 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
21932207
size = sizeof(struct snd_ump_endpoint_info);
21942208
else
21952209
size = sizeof(struct snd_ump_block_info);
2196-
cptr = snd_seq_client_use_ptr(client);
2210+
cptr = client_load_and_use_ptr(client);
21972211
if (!cptr)
21982212
return -ENOENT;
21992213

@@ -2475,7 +2489,7 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
24752489
if (check_event_type_and_length(ev))
24762490
return -EINVAL;
24772491

2478-
cptr = snd_seq_client_use_ptr(client);
2492+
cptr = client_load_and_use_ptr(client);
24792493
if (cptr == NULL)
24802494
return -EINVAL;
24812495

@@ -2707,7 +2721,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
27072721

27082722
/* list the client table */
27092723
for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
2710-
client = snd_seq_client_use_ptr(c);
2724+
client = client_load_and_use_ptr(c);
27112725
if (client == NULL)
27122726
continue;
27132727
if (client->type == NO_CLIENT) {

0 commit comments

Comments
 (0)