Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5a8fc06 authored by Hristo Venev's avatar Hristo Venev Committed by Greg Kroah-Hartman
Browse files

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: 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.name


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 91e21df6
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -2291,7 +2291,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;
@@ -2325,10 +2325,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);
@@ -2419,7 +2419,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:
@@ -2444,7 +2444,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);
+1 −1
Original line number Diff line number Diff line
@@ -2431,7 +2431,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,
+19 −12
Original line number Diff line number Diff line
@@ -1345,7 +1345,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;
@@ -1363,25 +1363,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,
	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;

	if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) {
		status = be_cmd_read_port_transceiver_data(adapter,
							   TR_PAGE_A2,
							   data +
							   PAGE_DATA_LEN);
		data += PAGE_DATA_LEN - begin;
		begin = 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);
}