On Tue, 12 Apr 2022 12:47:47 +0200, Takashi Sakamoto wrote: > > Hi, > > On Tue, Apr 12, 2022 at 11:31:40AM +0200, Takashi Iwai wrote: > > 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: e8ad415b7a55 ("ALSA: core: Add managed card creation") > > Cc: <stable@xxxxxxxxxxxxxxx> > > Signed-off-by: Takashi Iwai <tiwai@xxxxxxx> > > --- > > include/sound/core.h | 1 + > > sound/core/init.c | 28 ++++++++++++++++++++++++++++ > > 2 files changed, 29 insertions(+) > > > > diff --git a/include/sound/core.h b/include/sound/core.h > > index b7e9b58d3c78..6d4cc49584c6 100644 > > --- a/include/sound/core.h > > +++ b/include/sound/core.h > > @@ -284,6 +284,7 @@ int snd_card_disconnect(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_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); > > int snd_card_register(struct snd_card *card); > > int snd_card_info_init(void); > > diff --git a/sound/core/init.c b/sound/core/init.c > > index 31ba7024e3ad..726a8353201f 100644 > > --- a/sound/core/init.c > > +++ b/sound/core/init.c > > @@ -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() > > * is added automatically. In that way, the resource disconnection is assured > > * 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, > > 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); > > > > +/** > > + * 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, > > int idx, const char *xid, struct module *module, > > size_t extra_size) > > -- > > 2.31.1 > > The idea looks good itself to me. On the other hand, the name > 'snd_card_free_on_error()' is not so suitable since it assumes that > 'snd_devm_card_new()' is called in advance, while we have another function, > 'snd_card_new()'. > > I think it better to use 'snd_devm_card_free_on_error()' instead since > the function doesn't work as expected in the case of 'snd_card_new()' > (the snd_card_free() is not called because nothing found in devres). Yeah, that came to my mind in the first implementations, too, but it looked too long to me, so I took this term in the submitted version :) In theory, we can extend it to retrieve the card from the device data, too, but I don't think worth for it. thanks, Takashi