Skip to content

Commit 5d542b8

Browse files
Stefan Bindingtiwai
authored andcommitted
ALSA: hda: cs35l41: Cleanup and fix double free in firmware request
There is an unlikely but possible double free when loading firmware, and a missing free calls if a firmware is successfully requested but the coefficient file request fails, leading to the fallback firmware request occurring without clearing the previously loaded firmware. Fixes: cd40dad ("ALSA: hda: cs35l41: Ensure firmware/tuning pairs are always loaded") Reported-by: kernel test robot <[email protected]> Reported-by: Dan Carpenter <[email protected]> Closes: https://lore.kernel.org/r/[email protected]/ Signed-off-by: Stefan Binding <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 9c1a3f4 commit 5d542b8

File tree

1 file changed

+79
-36
lines changed

1 file changed

+79
-36
lines changed

sound/pci/hda/cs35l41_hda.c

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,14 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
185185
cs35l41->speaker_id, "wmfw");
186186
if (!ret) {
187187
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
188-
return cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
189-
CS35L41_FIRMWARE_ROOT,
190-
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
191-
cs35l41->speaker_id, "bin");
188+
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
189+
CS35L41_FIRMWARE_ROOT,
190+
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
191+
cs35l41->speaker_id, "bin");
192+
if (ret)
193+
goto coeff_err;
194+
195+
return 0;
192196
}
193197

194198
/* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
@@ -197,10 +201,14 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
197201
cs35l41->amp_name, -1, "wmfw");
198202
if (!ret) {
199203
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
200-
return cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
201-
CS35L41_FIRMWARE_ROOT,
202-
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
203-
cs35l41->speaker_id, "bin");
204+
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
205+
CS35L41_FIRMWARE_ROOT,
206+
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
207+
cs35l41->speaker_id, "bin");
208+
if (ret)
209+
goto coeff_err;
210+
211+
return 0;
204212
}
205213

206214
/* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
@@ -215,10 +223,14 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
215223
cs35l41->amp_name, cs35l41->speaker_id, "bin");
216224
if (ret)
217225
/* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
218-
return cs35l41_request_firmware_file(cs35l41, coeff_firmware,
219-
coeff_filename, CS35L41_FIRMWARE_ROOT,
220-
cs35l41->acpi_subsystem_id, NULL,
221-
cs35l41->speaker_id, "bin");
226+
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
227+
coeff_filename, CS35L41_FIRMWARE_ROOT,
228+
cs35l41->acpi_subsystem_id, NULL,
229+
cs35l41->speaker_id, "bin");
230+
if (ret)
231+
goto coeff_err;
232+
233+
return 0;
222234
}
223235

224236
/* try cirrus/part-dspN-fwtype-sub.wmfw */
@@ -233,12 +245,50 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
233245
cs35l41->speaker_id, "bin");
234246
if (ret)
235247
/* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
236-
return cs35l41_request_firmware_file(cs35l41, coeff_firmware,
237-
coeff_filename, CS35L41_FIRMWARE_ROOT,
238-
cs35l41->acpi_subsystem_id, NULL,
239-
cs35l41->speaker_id, "bin");
248+
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
249+
coeff_filename, CS35L41_FIRMWARE_ROOT,
250+
cs35l41->acpi_subsystem_id, NULL,
251+
cs35l41->speaker_id, "bin");
252+
if (ret)
253+
goto coeff_err;
254+
}
255+
256+
return ret;
257+
coeff_err:
258+
release_firmware(*wmfw_firmware);
259+
kfree(*wmfw_filename);
260+
return ret;
261+
}
262+
263+
static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41,
264+
const struct firmware **wmfw_firmware,
265+
char **wmfw_filename,
266+
const struct firmware **coeff_firmware,
267+
char **coeff_filename)
268+
{
269+
int ret;
270+
271+
/* Handle fallback */
272+
dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
273+
274+
/* fallback try cirrus/part-dspN-fwtype.wmfw */
275+
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
276+
CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
277+
if (ret)
278+
goto err;
279+
280+
/* fallback try cirrus/part-dspN-fwtype.bin */
281+
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
282+
CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
283+
if (ret) {
284+
release_firmware(*wmfw_firmware);
285+
kfree(*wmfw_filename);
286+
goto err;
240287
}
288+
return 0;
241289

290+
err:
291+
dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
242292
return ret;
243293
}
244294

@@ -254,7 +304,6 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
254304
ret = cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
255305
coeff_firmware, coeff_filename);
256306
goto out;
257-
258307
}
259308

260309
/* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
@@ -267,6 +316,9 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
267316
CS35L41_FIRMWARE_ROOT,
268317
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
269318
-1, "bin");
319+
if (ret)
320+
goto coeff_err;
321+
270322
goto out;
271323
}
272324

@@ -286,32 +338,23 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
286338
CS35L41_FIRMWARE_ROOT,
287339
cs35l41->acpi_subsystem_id, NULL, -1,
288340
"bin");
341+
if (ret)
342+
goto coeff_err;
289343
}
290344

291345
out:
292-
if (!ret)
293-
return 0;
346+
if (ret)
347+
/* if all attempts at finding firmware fail, try fallback */
348+
goto fallback;
294349

295-
/* Handle fallback */
296-
dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
350+
return 0;
297351

352+
coeff_err:
298353
release_firmware(*wmfw_firmware);
299354
kfree(*wmfw_filename);
300-
301-
/* fallback try cirrus/part-dspN-fwtype.wmfw */
302-
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
303-
CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
304-
if (!ret)
305-
/* fallback try cirrus/part-dspN-fwtype.bin */
306-
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
307-
CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
308-
309-
if (ret) {
310-
release_firmware(*wmfw_firmware);
311-
kfree(*wmfw_filename);
312-
dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
313-
}
314-
return ret;
355+
fallback:
356+
return cs35l41_fallback_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
357+
coeff_firmware, coeff_filename);
315358
}
316359

317360
#if IS_ENABLED(CONFIG_EFI)

0 commit comments

Comments
 (0)