| From 0cbe40112f42cf5e008f9127f6cd5952ba3946c7 Mon Sep 17 00:00:00 2001 |
| From: Johan Hovold <johan@kernel.org> |
| Date: Thu, 30 Mar 2017 12:15:37 +0200 |
| Subject: NFC: nfcmrvl: do not use device-managed resources |
| |
| From: Johan Hovold <johan@kernel.org> |
| |
| commit 0cbe40112f42cf5e008f9127f6cd5952ba3946c7 upstream. |
| |
| This specifically fixes resource leaks in the registration error paths. |
| |
| Device-managed resources is a bad fit for this driver as devices can be |
| registered from the n_nci line discipline. Firstly, a tty may not even |
| have a corresponding device (should it be part of a Unix98 pty) |
| something which would lead to a NULL-pointer dereference when |
| registering resources. |
| |
| Secondly, if the tty has a class device, its lifetime exceeds that of |
| the line discipline, which means that resources would leak every time |
| the line discipline is closed (or if registration fails). |
| |
| Currently, the devres interface was only being used to request a reset |
| gpio despite the fact that it was already explicitly freed in |
| nfcmrvl_nci_unregister_dev() (along with the private data), something |
| which also prevented the resource leak at close. |
| |
| Note that the driver treats gpio number 0 as invalid despite it being |
| perfectly valid. This will be addressed in a follow-up patch. |
| |
| Fixes: b2fe288eac72 ("NFC: nfcmrvl: free reset gpio") |
| Fixes: 4a2b947f56b3 ("NFC: nfcmrvl: add chip reset management") |
| Cc: Vincent Cuissard <cuissard@marvell.com> |
| Signed-off-by: Johan Hovold <johan@kernel.org> |
| Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/nfc/nfcmrvl/main.c | 19 +++++++++++-------- |
| 1 file changed, 11 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/nfc/nfcmrvl/main.c |
| +++ b/drivers/nfc/nfcmrvl/main.c |
| @@ -124,12 +124,13 @@ struct nfcmrvl_private *nfcmrvl_nci_regi |
| memcpy(&priv->config, pdata, sizeof(*pdata)); |
| |
| if (priv->config.reset_n_io) { |
| - rc = devm_gpio_request_one(dev, |
| - priv->config.reset_n_io, |
| - GPIOF_OUT_INIT_LOW, |
| - "nfcmrvl_reset_n"); |
| - if (rc < 0) |
| + rc = gpio_request_one(priv->config.reset_n_io, |
| + GPIOF_OUT_INIT_LOW, |
| + "nfcmrvl_reset_n"); |
| + if (rc < 0) { |
| + priv->config.reset_n_io = 0; |
| nfc_err(dev, "failed to request reset_n io\n"); |
| + } |
| } |
| |
| if (phy == NFCMRVL_PHY_SPI) { |
| @@ -154,7 +155,7 @@ struct nfcmrvl_private *nfcmrvl_nci_regi |
| if (!priv->ndev) { |
| nfc_err(dev, "nci_allocate_device failed\n"); |
| rc = -ENOMEM; |
| - goto error; |
| + goto error_free_gpio; |
| } |
| |
| nci_set_drvdata(priv->ndev, priv); |
| @@ -179,7 +180,9 @@ struct nfcmrvl_private *nfcmrvl_nci_regi |
| |
| error_free_dev: |
| nci_free_device(priv->ndev); |
| -error: |
| +error_free_gpio: |
| + if (priv->config.reset_n_io) |
| + gpio_free(priv->config.reset_n_io); |
| kfree(priv); |
| return ERR_PTR(rc); |
| } |
| @@ -195,7 +198,7 @@ void nfcmrvl_nci_unregister_dev(struct n |
| nfcmrvl_fw_dnld_deinit(priv); |
| |
| if (priv->config.reset_n_io) |
| - devm_gpio_free(priv->dev, priv->config.reset_n_io); |
| + gpio_free(priv->config.reset_n_io); |
| |
| nci_unregister_device(ndev); |
| nci_free_device(ndev); |