lkml.org 
[lkml]   [2022]   [Jul]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 063/105] be2net: Fix buffer overflow in be_get_module_eeprom
    Date
    From: Hristo Venev <hristo@venev.name>

    [ Upstream commit d7241f679a59cfe27f92cb5c6272cb429fb1f7ec ]

    be_cmd_read_port_transceiver_data assumes that it is given a buffer that
    is at least PAGE_DATA_LEN long, or twice that if the module supports SFF
    8472. However, this is not always the case.

    Fix this by passing the desired offset and length to
    be_cmd_read_port_transceiver_data so that we only copy the bytes once.

    Fixes: e36edd9d26cf ("be2net: add ethtool "-m" option support")
    Signed-off-by: Hristo Venev <hristo@venev.name>
    Link: https://lore.kernel.org/r/20220716085134.6095-1-hristo@venev.name
    Signed-off-by: Paolo Abeni <pabeni@redhat.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/net/ethernet/emulex/benet/be_cmds.c | 10 +++---
    drivers/net/ethernet/emulex/benet/be_cmds.h | 2 +-
    .../net/ethernet/emulex/benet/be_ethtool.c | 31 ++++++++++++-------
    3 files changed, 25 insertions(+), 18 deletions(-)

    diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
    index 649c5c429bd7..1288b5e3d220 100644
    --- a/drivers/net/ethernet/emulex/benet/be_cmds.c
    +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
    @@ -2287,7 +2287,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)

    /* Uses sync mcc */
    int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
    - u8 page_num, u8 *data)
    + u8 page_num, u32 off, u32 len, u8 *data)
    {
    struct be_dma_mem cmd;
    struct be_mcc_wrb *wrb;
    @@ -2321,10 +2321,10 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
    req->port = cpu_to_le32(adapter->hba_port_num);
    req->page_num = cpu_to_le32(page_num);
    status = be_mcc_notify_wait(adapter);
    - if (!status) {
    + if (!status && len > 0) {
    struct be_cmd_resp_port_type *resp = cmd.va;

    - memcpy(data, resp->page_data, PAGE_DATA_LEN);
    + memcpy(data, resp->page_data + off, len);
    }
    err:
    mutex_unlock(&adapter->mcc_lock);
    @@ -2415,7 +2415,7 @@ int be_cmd_query_cable_type(struct be_adapter *adapter)
    int status;

    status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
    - page_data);
    + 0, PAGE_DATA_LEN, page_data);
    if (!status) {
    switch (adapter->phy.interface_type) {
    case PHY_TYPE_QSFP:
    @@ -2440,7 +2440,7 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter)
    int status;

    status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
    - page_data);
    + 0, PAGE_DATA_LEN, page_data);
    if (!status) {
    strlcpy(adapter->phy.vendor_name, page_data +
    SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
    diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
    index c30d6d6f0f3a..9e17d6a7ab8c 100644
    --- a/drivers/net/ethernet/emulex/benet/be_cmds.h
    +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
    @@ -2427,7 +2427,7 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon,
    int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
    u32 *state);
    int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
    - u8 page_num, u8 *data);
    + u8 page_num, u32 off, u32 len, u8 *data);
    int be_cmd_query_cable_type(struct be_adapter *adapter);
    int be_cmd_query_sfp_info(struct be_adapter *adapter);
    int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
    diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
    index 99cc1c46fb30..d90bf457e49c 100644
    --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
    +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
    @@ -1338,7 +1338,7 @@ static int be_get_module_info(struct net_device *netdev,
    return -EOPNOTSUPP;

    status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
    - page_data);
    + 0, PAGE_DATA_LEN, page_data);
    if (!status) {
    if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
    modinfo->type = ETH_MODULE_SFF_8079;
    @@ -1356,25 +1356,32 @@ static int be_get_module_eeprom(struct net_device *netdev,
    {
    struct be_adapter *adapter = netdev_priv(netdev);
    int status;
    + u32 begin, end;

    if (!check_privilege(adapter, MAX_PRIVILEGES))
    return -EOPNOTSUPP;

    - status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
    - data);
    - if (status)
    - goto err;
    + begin = eeprom->offset;
    + end = eeprom->offset + eeprom->len;
    +
    + if (begin < PAGE_DATA_LEN) {
    + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, begin,
    + min_t(u32, end, PAGE_DATA_LEN) - begin,
    + data);
    + if (status)
    + goto err;
    +
    + data += PAGE_DATA_LEN - begin;
    + begin = PAGE_DATA_LEN;
    + }

    - if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) {
    - status = be_cmd_read_port_transceiver_data(adapter,
    - TR_PAGE_A2,
    - data +
    - PAGE_DATA_LEN);
    + if (end > PAGE_DATA_LEN) {
    + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2,
    + begin - PAGE_DATA_LEN,
    + end - begin, data);
    if (status)
    goto err;
    }
    - if (eeprom->offset)
    - memcpy(data, data + eeprom->offset, eeprom->len);
    err:
    return be_cmd_status(status);
    }
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-07-27 18:55    [W:4.147 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site