ALSA: core: Add snd_card_free_on_error() helper
This is a small helper function to handle the error path more easily
when an error happens during the probe for the device with the
device-managed card. Since devres releases in the reverser order of
the creations, usually snd_card_free() gets called at the last in the
probe error path unless it already reached snd_card_register() calls.
Due to this nature, when a driver expects the resource releases in
card->private_free, this might be called too lately.
As a workaround, one should call the probe like:
static int __some_probe(...) { // do real probe.... }
static int some_probe(...)
{
return snd_card_free_on_error(dev, __some_probe(dev, ...));
}
so that the snd_card_free() is called explicitly at the beginning of
the error path from the probe.
This function will be used in the upcoming fixes to address the
regressions by devres usages.
Fixes: e8ad415b7a
("ALSA: core: Add managed card creation")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20220412093141.8008-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
264fb03497
commit
fee2b871d8
|
@ -284,6 +284,7 @@ int snd_card_disconnect(struct snd_card *card);
|
||||||
void snd_card_disconnect_sync(struct snd_card *card);
|
void snd_card_disconnect_sync(struct snd_card *card);
|
||||||
int snd_card_free(struct snd_card *card);
|
int snd_card_free(struct snd_card *card);
|
||||||
int snd_card_free_when_closed(struct snd_card *card);
|
int snd_card_free_when_closed(struct snd_card *card);
|
||||||
|
int snd_card_free_on_error(struct device *dev, int ret);
|
||||||
void snd_card_set_id(struct snd_card *card, const char *id);
|
void snd_card_set_id(struct snd_card *card, const char *id);
|
||||||
int snd_card_register(struct snd_card *card);
|
int snd_card_register(struct snd_card *card);
|
||||||
int snd_card_info_init(void);
|
int snd_card_info_init(void);
|
||||||
|
|
|
@ -209,6 +209,12 @@ static void __snd_card_release(struct device *dev, void *data)
|
||||||
* snd_card_register(), the very first devres action to call snd_card_free()
|
* snd_card_register(), the very first devres action to call snd_card_free()
|
||||||
* is added automatically. In that way, the resource disconnection is assured
|
* is added automatically. In that way, the resource disconnection is assured
|
||||||
* at first, then released in the expected order.
|
* at first, then released in the expected order.
|
||||||
|
*
|
||||||
|
* If an error happens at the probe before snd_card_register() is called and
|
||||||
|
* there have been other devres resources, you'd need to free the card manually
|
||||||
|
* via snd_card_free() call in the error; otherwise it may lead to UAF due to
|
||||||
|
* devres call orders. You can use snd_card_free_on_error() helper for
|
||||||
|
* handling it more easily.
|
||||||
*/
|
*/
|
||||||
int snd_devm_card_new(struct device *parent, int idx, const char *xid,
|
int snd_devm_card_new(struct device *parent, int idx, const char *xid,
|
||||||
struct module *module, size_t extra_size,
|
struct module *module, size_t extra_size,
|
||||||
|
@ -235,6 +241,28 @@ int snd_devm_card_new(struct device *parent, int idx, const char *xid,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_devm_card_new);
|
EXPORT_SYMBOL_GPL(snd_devm_card_new);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_card_free_on_error - a small helper for handling devm probe errors
|
||||||
|
* @dev: the managed device object
|
||||||
|
* @ret: the return code from the probe callback
|
||||||
|
*
|
||||||
|
* This function handles the explicit snd_card_free() call at the error from
|
||||||
|
* the probe callback. It's just a small helper for simplifying the error
|
||||||
|
* handling with the managed devices.
|
||||||
|
*/
|
||||||
|
int snd_card_free_on_error(struct device *dev, int ret)
|
||||||
|
{
|
||||||
|
struct snd_card *card;
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
card = devres_find(dev, __snd_card_release, NULL, NULL);
|
||||||
|
if (card)
|
||||||
|
snd_card_free(card);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(snd_card_free_on_error);
|
||||||
|
|
||||||
static int snd_card_init(struct snd_card *card, struct device *parent,
|
static int snd_card_init(struct snd_card *card, struct device *parent,
|
||||||
int idx, const char *xid, struct module *module,
|
int idx, const char *xid, struct module *module,
|
||||||
size_t extra_size)
|
size_t extra_size)
|
||||||
|
|
Loading…
Reference in New Issue