Commit d7241f67 authored by Hristo Venev's avatar Hristo Venev Committed by Paolo Abeni

be2net: Fix buffer overflow in be_get_module_eeprom

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: e36edd9d ("be2net: add ethtool "-m" option support")
Signed-off-by: default avatarHristo Venev <hristo@venev.name>
Link: https://lore.kernel.org/r/20220716085134.6095-1-hristo@venev.nameSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent da791bac
...@@ -2287,7 +2287,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) ...@@ -2287,7 +2287,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
/* 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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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,
......
...@@ -1344,7 +1344,7 @@ static int be_get_module_info(struct net_device *netdev, ...@@ -1344,7 +1344,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;
...@@ -1362,25 +1362,32 @@ static int be_get_module_eeprom(struct net_device *netdev, ...@@ -1362,25 +1362,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;
data); end = eeprom->offset + eeprom->len;
if (status)
goto err; 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) { if (end > PAGE_DATA_LEN) {
status = be_cmd_read_port_transceiver_data(adapter, status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2,
TR_PAGE_A2, begin - PAGE_DATA_LEN,
data + end - begin, data);
PAGE_DATA_LEN);
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);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment