Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Hristo Venev and committed by
Paolo Abeni
d7241f67 da791bac

+25 -18
+5 -5
drivers/net/ethernet/emulex/benet/be_cmds.c
··· 2287 2287 2288 2288 /* Uses sync mcc */ 2289 2289 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, 2290 - u8 page_num, u8 *data) 2290 + u8 page_num, u32 off, u32 len, u8 *data) 2291 2291 { 2292 2292 struct be_dma_mem cmd; 2293 2293 struct be_mcc_wrb *wrb; ··· 2321 2321 req->port = cpu_to_le32(adapter->hba_port_num); 2322 2322 req->page_num = cpu_to_le32(page_num); 2323 2323 status = be_mcc_notify_wait(adapter); 2324 - if (!status) { 2324 + if (!status && len > 0) { 2325 2325 struct be_cmd_resp_port_type *resp = cmd.va; 2326 2326 2327 - memcpy(data, resp->page_data, PAGE_DATA_LEN); 2327 + memcpy(data, resp->page_data + off, len); 2328 2328 } 2329 2329 err: 2330 2330 mutex_unlock(&adapter->mcc_lock); ··· 2415 2415 int status; 2416 2416 2417 2417 status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, 2418 - page_data); 2418 + 0, PAGE_DATA_LEN, page_data); 2419 2419 if (!status) { 2420 2420 switch (adapter->phy.interface_type) { 2421 2421 case PHY_TYPE_QSFP: ··· 2440 2440 int status; 2441 2441 2442 2442 status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, 2443 - page_data); 2443 + 0, PAGE_DATA_LEN, page_data); 2444 2444 if (!status) { 2445 2445 strlcpy(adapter->phy.vendor_name, page_data + 2446 2446 SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
+1 -1
drivers/net/ethernet/emulex/benet/be_cmds.h
··· 2427 2427 int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, 2428 2428 u32 *state); 2429 2429 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, 2430 - u8 page_num, u8 *data); 2430 + u8 page_num, u32 off, u32 len, u8 *data); 2431 2431 int be_cmd_query_cable_type(struct be_adapter *adapter); 2432 2432 int be_cmd_query_sfp_info(struct be_adapter *adapter); 2433 2433 int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+19 -12
drivers/net/ethernet/emulex/benet/be_ethtool.c
··· 1344 1344 return -EOPNOTSUPP; 1345 1345 1346 1346 status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, 1347 - page_data); 1347 + 0, PAGE_DATA_LEN, page_data); 1348 1348 if (!status) { 1349 1349 if (!page_data[SFP_PLUS_SFF_8472_COMP]) { 1350 1350 modinfo->type = ETH_MODULE_SFF_8079; ··· 1362 1362 { 1363 1363 struct be_adapter *adapter = netdev_priv(netdev); 1364 1364 int status; 1365 + u32 begin, end; 1365 1366 1366 1367 if (!check_privilege(adapter, MAX_PRIVILEGES)) 1367 1368 return -EOPNOTSUPP; 1368 1369 1369 - status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, 1370 - data); 1371 - if (status) 1372 - goto err; 1370 + begin = eeprom->offset; 1371 + end = eeprom->offset + eeprom->len; 1373 1372 1374 - if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) { 1375 - status = be_cmd_read_port_transceiver_data(adapter, 1376 - TR_PAGE_A2, 1377 - data + 1378 - PAGE_DATA_LEN); 1373 + if (begin < PAGE_DATA_LEN) { 1374 + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, begin, 1375 + min_t(u32, end, PAGE_DATA_LEN) - begin, 1376 + data); 1377 + if (status) 1378 + goto err; 1379 + 1380 + data += PAGE_DATA_LEN - begin; 1381 + begin = PAGE_DATA_LEN; 1382 + } 1383 + 1384 + if (end > PAGE_DATA_LEN) { 1385 + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2, 1386 + begin - PAGE_DATA_LEN, 1387 + end - begin, data); 1379 1388 if (status) 1380 1389 goto err; 1381 1390 } 1382 - if (eeprom->offset) 1383 - memcpy(data, data + eeprom->offset, eeprom->len); 1384 1391 err: 1385 1392 return be_cmd_status(status); 1386 1393 }