be2net: Fix buffer overflow in be_get_module_eeprom
[ 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: e36edd9d26
("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>
This commit is contained in:
parent
91d6aa19dd
commit
a8569f76df
@ -2287,7 +2287,7 @@ err:
|
|||||||
|
|
||||||
/* Uses sync mcc */
|
/* Uses sync mcc */
|
||||||
int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
|
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_dma_mem cmd;
|
||||||
struct be_mcc_wrb *wrb;
|
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->port = cpu_to_le32(adapter->hba_port_num);
|
||||||
req->page_num = cpu_to_le32(page_num);
|
req->page_num = cpu_to_le32(page_num);
|
||||||
status = be_mcc_notify_wait(adapter);
|
status = be_mcc_notify_wait(adapter);
|
||||||
if (!status) {
|
if (!status && len > 0) {
|
||||||
struct be_cmd_resp_port_type *resp = cmd.va;
|
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:
|
err:
|
||||||
mutex_unlock(&adapter->mcc_lock);
|
mutex_unlock(&adapter->mcc_lock);
|
||||||
@ -2415,7 +2415,7 @@ int be_cmd_query_cable_type(struct be_adapter *adapter)
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
||||||
page_data);
|
0, PAGE_DATA_LEN, page_data);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
switch (adapter->phy.interface_type) {
|
switch (adapter->phy.interface_type) {
|
||||||
case PHY_TYPE_QSFP:
|
case PHY_TYPE_QSFP:
|
||||||
@ -2440,7 +2440,7 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter)
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
||||||
page_data);
|
0, PAGE_DATA_LEN, page_data);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
strlcpy(adapter->phy.vendor_name, page_data +
|
strlcpy(adapter->phy.vendor_name, page_data +
|
||||||
SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
|
SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
|
||||||
|
@ -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,
|
int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
|
||||||
u32 *state);
|
u32 *state);
|
||||||
int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
|
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_cable_type(struct be_adapter *adapter);
|
||||||
int be_cmd_query_sfp_info(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,
|
int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
|
||||||
|
@ -1339,7 +1339,7 @@ static int be_get_module_info(struct net_device *netdev,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
||||||
page_data);
|
0, PAGE_DATA_LEN, page_data);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
|
if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
|
||||||
modinfo->type = ETH_MODULE_SFF_8079;
|
modinfo->type = ETH_MODULE_SFF_8079;
|
||||||
@ -1357,25 +1357,32 @@ static int be_get_module_eeprom(struct net_device *netdev,
|
|||||||
{
|
{
|
||||||
struct be_adapter *adapter = netdev_priv(netdev);
|
struct be_adapter *adapter = netdev_priv(netdev);
|
||||||
int status;
|
int status;
|
||||||
|
u32 begin, end;
|
||||||
|
|
||||||
if (!check_privilege(adapter, MAX_PRIVILEGES))
|
if (!check_privilege(adapter, MAX_PRIVILEGES))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
|
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);
|
data);
|
||||||
if (status)
|
if (status)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) {
|
data += PAGE_DATA_LEN - begin;
|
||||||
status = be_cmd_read_port_transceiver_data(adapter,
|
begin = PAGE_DATA_LEN;
|
||||||
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)
|
if (status)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (eeprom->offset)
|
|
||||||
memcpy(data, data + eeprom->offset, eeprom->len);
|
|
||||||
err:
|
err:
|
||||||
return be_cmd_status(status);
|
return be_cmd_status(status);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user