lkml.org 
[lkml]   [2020]   [Jun]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 092/314] scsi: qedf: Fix crash when MFW calls for protocol stats while function is still probing
    Date
    From: Chad Dupuis <cdupuis@marvell.com>

    [ Upstream commit ad40f5256095c68dc17c991eb976261d5ea2daaa ]

    The MFW may make a call to qed and then to qedf for protocol statistics
    while the function is still probing. If this happens it's possible that
    some members of the struct qedf_ctx may not be fully initialized which can
    result in a NULL pointer dereference or general protection fault.

    To prevent this, add a new flag call QEDF_PROBING and set it when the
    __qedf_probe() function is active. Then in the qedf_get_protocol_tlv_data()
    function we can check if the function is still probing and return
    immediantely before any uninitialized structures can be touched.

    Link: https://lore.kernel.org/r/20200416084314.18851-9-skashyap@marvell.com
    Signed-off-by: Chad Dupuis <cdupuis@marvell.com>
    Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/scsi/qedf/qedf.h | 1 +
    drivers/scsi/qedf/qedf_main.c | 35 +++++++++++++++++++++++++++++++----
    2 files changed, 32 insertions(+), 4 deletions(-)

    diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h
    index f3f399fe10c86..0da4e16fb23a6 100644
    --- a/drivers/scsi/qedf/qedf.h
    +++ b/drivers/scsi/qedf/qedf.h
    @@ -355,6 +355,7 @@ struct qedf_ctx {
    #define QEDF_GRCDUMP_CAPTURE 4
    #define QEDF_IN_RECOVERY 5
    #define QEDF_DBG_STOP_IO 6
    +#define QEDF_PROBING 8
    unsigned long flags; /* Miscellaneous state flags */
    int fipvlan_retries;
    u8 num_queues;
    diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
    index 59ca98f12afd5..3d0e345947c1f 100644
    --- a/drivers/scsi/qedf/qedf_main.c
    +++ b/drivers/scsi/qedf/qedf_main.c
    @@ -3153,7 +3153,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
    {
    int rc = -EINVAL;
    struct fc_lport *lport;
    - struct qedf_ctx *qedf;
    + struct qedf_ctx *qedf = NULL;
    struct Scsi_Host *host;
    bool is_vf = false;
    struct qed_ll2_params params;
    @@ -3183,6 +3183,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)

    /* Initialize qedf_ctx */
    qedf = lport_priv(lport);
    + set_bit(QEDF_PROBING, &qedf->flags);
    qedf->lport = lport;
    qedf->ctlr.lp = lport;
    qedf->pdev = pdev;
    @@ -3206,9 +3207,12 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
    } else {
    /* Init pointers during recovery */
    qedf = pci_get_drvdata(pdev);
    + set_bit(QEDF_PROBING, &qedf->flags);
    lport = qedf->lport;
    }

    + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe started.\n");
    +
    host = lport->host;

    /* Allocate mempool for qedf_io_work structs */
    @@ -3513,6 +3517,10 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
    else
    fc_fabric_login(lport);

    + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");
    +
    + clear_bit(QEDF_PROBING, &qedf->flags);
    +
    /* All good */
    return 0;

    @@ -3538,6 +3546,11 @@ err2:
    err1:
    scsi_host_put(lport->host);
    err0:
    + if (qedf) {
    + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");
    +
    + clear_bit(QEDF_PROBING, &qedf->flags);
    + }
    return rc;
    }

    @@ -3687,11 +3700,25 @@ void qedf_get_protocol_tlv_data(void *dev, void *data)
    {
    struct qedf_ctx *qedf = dev;
    struct qed_mfw_tlv_fcoe *fcoe = data;
    - struct fc_lport *lport = qedf->lport;
    - struct Scsi_Host *host = lport->host;
    - struct fc_host_attrs *fc_host = shost_to_fc_host(host);
    + struct fc_lport *lport;
    + struct Scsi_Host *host;
    + struct fc_host_attrs *fc_host;
    struct fc_host_statistics *hst;

    + if (!qedf) {
    + QEDF_ERR(NULL, "qedf is null.\n");
    + return;
    + }
    +
    + if (test_bit(QEDF_PROBING, &qedf->flags)) {
    + QEDF_ERR(&qedf->dbg_ctx, "Function is still probing.\n");
    + return;
    + }
    +
    + lport = qedf->lport;
    + host = lport->host;
    + fc_host = shost_to_fc_host(host);
    +
    /* Force a refresh of the fc_host stats including offload stats */
    hst = qedf_fc_get_host_stats(host);

    --
    2.25.1


    \
     
     \ /
      Last update: 2020-06-23 23:20    [W:6.909 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site