From 247613d6ce92059ab891ea4f40b1e3da9f591856 Mon Sep 17 00:00:00 2001 From: Sanath Kumar Gampa Date: Thu, 28 Nov 2024 05:20:12 +0000 Subject: [PATCH] nvethernet: fix top-25 issues Fixed below issues -FORWARD_NULL -CERT STR07-C -CERT INT32-C -CERT INT30-C -CERT INT08-C -CERT EXP39-C -CERT EXP34-C JIRA NET-2044 Change-Id: I839bd5aedff30c7e9679f513a2cf7a1fbe3b2b8a Signed-off-by: Sanath Kumar Gampa Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3258684 Reviewed-by: Ashutosh Jha Reviewed-by: Mohan Thadikamalla GVS: buildbot_gerritrpt --- .../ethernet/nvidia/nvethernet/ether_linux.c | 124 +++++++++++++++--- .../ethernet/nvidia/nvethernet/ether_linux.h | 20 ++- .../net/ethernet/nvidia/nvethernet/ethtool.c | 61 ++++++--- .../net/ethernet/nvidia/nvethernet/macsec.c | 14 +- .../net/ethernet/nvidia/nvethernet/macsec.h | 9 +- drivers/net/ethernet/nvidia/nvethernet/osd.c | 54 +++++--- .../ethernet/nvidia/nvethernet/selftests.c | 19 +-- .../net/ethernet/nvidia/nvethernet/sysfs.c | 31 +++-- 8 files changed, 256 insertions(+), 76 deletions(-) diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index aaf62520..57e81b61 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -2013,6 +2013,12 @@ static int ether_request_irqs(struct ether_priv_data *pdata) if (osi_core->mac_ver > OSI_EQOS_MAC_5_00 || osi_core->mac != OSI_MAC_HW_EQOS) { for (i = 0; i < osi_core->num_vm_irqs; i++) { + // Need to get reviewd for these checks + if ((j >= ETHER_IRQ_MAX_IDX) || (i >= OSI_MAX_VM_IRQS)) { + dev_err(pdata->dev, + "unexpected irq name index received (%d)\n", j); + goto err_chan_irq; + } snprintf(pdata->irq_names[j], ETHER_IRQ_NAME_SZ, "%s.vm%d", netdev_name(pdata->ndev), i); ret = devm_request_irq(pdata->dev, pdata->vm_irqs[i], @@ -2031,8 +2037,12 @@ static int ether_request_irqs(struct ether_priv_data *pdata) } } else { for (i = 0; i < osi_dma->num_dma_chans; i++) { + if (j >= (ETHER_IRQ_MAX_IDX - 1)) { + dev_err(pdata->dev, + "unexpected irq name index received (%d)\n", j); + goto err_chan_irq; + } chan = osi_dma->dma_chans[i]; - snprintf(pdata->irq_names[j], ETHER_IRQ_NAME_SZ, "%s.rx%d", netdev_name(pdata->ndev), chan); ret = devm_request_irq(pdata->dev, pdata->rx_irqs[i], @@ -2826,7 +2836,9 @@ static int ether_update_mac_addr_filter(struct ether_priv_data *pdata, static u32 ether_mdio_c45_addr(int devad, u16 regnum) { - return OSI_MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum; + unsigned int udevad = (unsigned int)devad & 0x7FFFU; + + return OSI_MII_ADDR_C45 | (udevad << MII_DEVADDR_C45_SHIFT) | regnum; } /** @@ -3457,19 +3469,21 @@ int ether_close(struct net_device *ndev) * @retval 1 on success * @retval "negative value" on failure. */ -static int ether_handle_tso(struct osi_tx_pkt_cx *tx_pkt_cx, +static int ether_handle_tso(struct device *dev, + struct osi_tx_pkt_cx *tx_pkt_cx, struct sk_buff *skb) { int ret = 1; if (skb_is_gso(skb) == 0) { - return 0; + ret = 0; + goto func_exit; } if (skb_header_cloned(skb)) { ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - if (ret) { - return ret; + if (ret != 0) { + goto func_exit; } } @@ -3482,16 +3496,28 @@ static int ether_handle_tso(struct osi_tx_pkt_cx *tx_pkt_cx, tx_pkt_cx->tcp_udp_hdrlen = tcp_hdrlen(skb); tx_pkt_cx->mss = skb_shinfo(skb)->gso_size; } + if ((UINT_MAX - skb_transport_offset(skb)) < tx_pkt_cx->tcp_udp_hdrlen) { + dev_err(dev, "Unexpected udp hdr length\n"); + ret = -EINVAL; // return failure in boundary condition + goto func_exit; + } tx_pkt_cx->total_hdrlen = skb_transport_offset(skb) + tx_pkt_cx->tcp_udp_hdrlen; - tx_pkt_cx->payload_len = (skb->len - tx_pkt_cx->total_hdrlen); + if (tx_pkt_cx->total_hdrlen > skb->len) { + dev_err(dev, "Unexpected total hdr length\n"); + ret = -EINVAL; // return failure in boundary condition + goto func_exit; + } else { + tx_pkt_cx->payload_len = (skb->len - tx_pkt_cx->total_hdrlen); + } netdev_dbg(skb->dev, "mss =%u\n", tx_pkt_cx->mss); netdev_dbg(skb->dev, "payload_len =%u\n", tx_pkt_cx->payload_len); netdev_dbg(skb->dev, "tcp_udp_hdrlen=%u\n", tx_pkt_cx->tcp_udp_hdrlen); netdev_dbg(skb->dev, "total_hdrlen =%u\n", tx_pkt_cx->total_hdrlen); - return 1; +func_exit: + return ret; } /** @@ -3517,6 +3543,10 @@ static void ether_tx_swcx_rollback(struct ether_priv_data *pdata, struct osi_tx_swcx *tx_swcx = NULL; while (count > 0) { + if ((pdata->osi_dma->tx_ring_sz == 0U) || (cur_tx_idx == 0U)) { + dev_err(dev, "Invalid Tx ring size or index\n"); + break; + } DECR_TX_DESC_INDEX(cur_tx_idx, pdata->osi_dma->tx_ring_sz); tx_swcx = tx_ring->tx_swcx + cur_tx_idx; if (tx_swcx->buf_phy_addr) { @@ -3568,11 +3598,13 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, memset(tx_pkt_cx, 0, sizeof(*tx_pkt_cx)); - ret = ether_handle_tso(tx_pkt_cx, skb); + // Need to get reviewed aboyut this properly + ret = ether_handle_tso(dev, tx_pkt_cx, skb); + if (unlikely(ret < 0)) { dev_err(dev, "Unable to handle TSO packet (%d)\n", ret); /* Caller will take care of consuming skb */ - return ret; + goto exit_func; } if (ret == 0) { @@ -3597,6 +3629,10 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, tx_pkt_cx->flags |= OSI_PKT_CX_PTP; } + if (pdata->osi_dma->tx_ring_sz == 0U) { + dev_err(dev, "Invalid Tx ring size\n"); + goto exit_func; + } if (((tx_pkt_cx->flags & OSI_PKT_CX_VLAN) == OSI_PKT_CX_VLAN) || ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO) || (((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) && @@ -3606,7 +3642,8 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, OSI_PTP_SYNC_ONESTEP)))) { tx_swcx = tx_ring->tx_swcx + cur_tx_idx; if (tx_swcx->len) { - return 0; + ret = 0; + goto exit_func; } tx_swcx->len = -1; @@ -3647,6 +3684,11 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, tx_swcx->len = size; len -= size; offset += size; + if (cnt == (int)INT_MAX) { + dev_err(dev, "Reached Max desc count\n"); + ret = -ENOMEM; + goto dma_map_failed; + } cnt++; INCR_TX_DESC_INDEX(cur_tx_idx, pdata->osi_dma->tx_ring_sz); } @@ -3678,7 +3720,19 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, tx_swcx->flags &= ~OSI_PKT_CX_PAGED_BUF; tx_swcx->len = size; len -= size; + if (offset > UINT_MAX - size) { + dev_err(dev, "Offset addition overflow detected:" + "size = %u, offset = %u\n", + size, offset); + ret = -ENOMEM; + goto dma_map_failed; + } offset += size; + if (cnt == (int)INT_MAX) { + dev_err(dev, "Reached Max desc count\n"); + ret = -ENOMEM; + goto dma_map_failed; + } cnt++; INCR_TX_DESC_INDEX(cur_tx_idx, pdata->osi_dma->tx_ring_sz); } @@ -3697,6 +3751,12 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, } size = min(len, max_data_len_per_txd); + if (skb_frag_off(frag) > UINT_MAX - offset) { + dev_err(dev, "Offset addition overflow detected:" + "frag offset = %u, offset = %u\n", + skb_frag_off(frag), offset); + return -ENOMEM; + } page_idx = (skb_frag_off(frag) + offset) >> PAGE_SHIFT; page_offset = (skb_frag_off(frag) + offset) & ~PAGE_MASK; tx_swcx->buf_phy_addr = dma_map_page(dev, @@ -3714,6 +3774,11 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, tx_swcx->len = size; len -= size; offset += size; + if (cnt == (int)INT_MAX) { + dev_err(dev, "Reached Max desc count\n"); + ret = -ENOMEM; + goto dma_map_failed; + } cnt++; INCR_TX_DESC_INDEX(cur_tx_idx, pdata->osi_dma->tx_ring_sz); } @@ -3730,6 +3795,7 @@ desc_not_free: dma_map_failed: /* Failed to fill current desc. Rollback previous desc's */ ether_tx_swcx_rollback(pdata, tx_ring, cur_tx_idx, cnt); +exit_func: return ret; } @@ -3954,7 +4020,7 @@ static int ether_prepare_uc_list(struct net_device *dev, if (ioctl_data == NULL) { dev_err(pdata->dev, "ioctl_data is NULL\n"); - return ret; + goto exit_func; } memset(&ioctl_data->l2_filter, 0x0, sizeof(struct osi_filter)); @@ -3971,6 +4037,11 @@ static int ether_prepare_uc_list(struct net_device *dev, return osi_handle_ioctl(osi_core, ioctl_data); } #endif /* !OSI_STRIPPED_LIB */ + if (i > pdata->num_mac_addr_regs) { + dev_err(pdata->dev, "Invalid value: i (%u) exceeds num_mac_addr_regs (%u)\n", + i, pdata->num_mac_addr_regs); + goto exit_func; + } if (netdev_uc_count(dev) > (pdata->num_mac_addr_regs - i)) { /* switch to PROMISCUOUS mode */ ioctl_data->l2_filter.oper_mode = (OSI_OPER_DIS_PERFECT | @@ -4028,6 +4099,7 @@ static int ether_prepare_uc_list(struct net_device *dev, *mac_addr_idx = i; } +exit_func: return ret; } @@ -4980,8 +5052,8 @@ static int ether_get_vm_irq_data(struct platform_device *pdev, { struct osi_core_priv_data *osi_core = pdata->osi_core; struct device_node *vm_node, *temp; - unsigned int i, j, node = 0; - int vm_irq_id, child_id, ret =0; + unsigned int i, j, node = 0, vm_irq_id, child_id; + int ret = 0; vm_node = of_parse_phandle(pdev->dev.of_node, "nvidia,vm-irq-config", 0); @@ -5063,6 +5135,8 @@ static int ether_get_vm_irq_data(struct platform_device *pdev, } } + /* Assuming there would not be more than 0xFFFF nodes */ + child_id &= MAX_CHILD_NODES; child_id++; } @@ -5128,6 +5202,11 @@ static int ether_get_irqs(struct platform_device *pdev, } else { /* get TX IRQ numbers */ for (i = 0, j = 1; i < num_chans; i++) { + if (j == UINT_MAX) { + dev_err(pdata->dev, "Index j exceeded maximum value\n"); + ret = -1; + goto exit_func; + } pdata->tx_irqs[i] = platform_get_irq(pdev, j++); if (pdata->tx_irqs[i] < 0) { dev_err(&pdev->dev, "failed to get TX IRQ number\n"); @@ -5136,6 +5215,11 @@ static int ether_get_irqs(struct platform_device *pdev, } for (i = 0; i < num_chans; i++) { + if (j == UINT_MAX) { + dev_err(pdata->dev, "Index j exceeded maximum value\n"); + ret = -1; + goto exit_func; + } pdata->rx_irqs[i] = platform_get_irq(pdev, j++); if (pdata->rx_irqs[i] < 0) { dev_err(&pdev->dev, "failed to get RX IRQ number\n"); @@ -5144,7 +5228,10 @@ static int ether_get_irqs(struct platform_device *pdev, } } - return 0; + ret = 0; + +exit_func: + return ret; } /** @@ -5299,6 +5386,12 @@ static int ether_get_mac_address(struct ether_priv_data *pdata) eth_mac_addr = addr; } + /* Added below to fix FORWARD_NULL Static analysis error */ + if (eth_mac_addr == NULL) { + ret = -EINVAL; + goto exit_func; + } + /* Found a valid mac address */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) dev_addr_mod(ndev, 0, eth_mac_addr, ETH_ALEN); @@ -5309,6 +5402,7 @@ static int ether_get_mac_address(struct ether_priv_data *pdata) dev_info(dev, "Ethernet MAC address: %pM\n", ndev->dev_addr); +exit_func: return ret; } diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h index b1fd6687..ff14ee26 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h @@ -95,6 +95,16 @@ */ #define ETH_MAC_STR_LEN 20 +/** + * @addtogroup Maximum number of child nodes + */ +#define MAX_CHILD_NODES 0xFFFFU + +/** + * @addtogroup Helper for INT_32 MAX + */ +#define OSD_INT_MAX 0x7FFFFFFF + /** * @addtogroup Ethernet Transmit Queue Priority * @@ -308,8 +318,14 @@ static inline bool valid_tx_len(unsigned int length) static inline int ether_avail_txdesc_cnt(struct osi_dma_priv_data *osi_dma, struct osi_tx_ring *tx_ring) { - return ((tx_ring->clean_idx - tx_ring->cur_tx_idx - 1) & - (osi_dma->tx_ring_sz - 1)); + int ret = -EINVAL; + + if ((osi_dma->tx_ring_sz == 0U) || (tx_ring->cur_tx_idx == 0U) || + (tx_ring->clean_idx < (tx_ring->cur_tx_idx - 1U))) { + return ret; + } + return ((tx_ring->clean_idx - tx_ring->cur_tx_idx - 1U) & + (osi_dma->tx_ring_sz - 1U)); } /** diff --git a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c index f7cca24b..6b3b9dff 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c @@ -1030,6 +1030,23 @@ static const struct ether_stats ether_tstrings_stats[] = { #endif /* OSI_STRIPPED_LIB */ }; +static u64 counter_helper(u64 sizeof_stat, char *p) +{ + u64 ret = 0; + + if (sizeof_stat == sizeof(u64)) { + u64 temp = 0; + (void)memcpy(&temp, (void *)p, sizeof(temp)); + ret = temp; + } else { + u32 temp = 0; + (void)memcpy(&temp, (void *)p, sizeof(temp)); + ret = temp; + } + + return ret; +} + void ether_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 *data) @@ -1077,18 +1094,18 @@ void ether_get_ethtool_stats(struct net_device *dev, for (i = 0; i < ETHER_MMC_STATS_LEN; i++) { char *p = (char *)osi_core + ether_mmc[i].stat_offset; - - data[j++] = (ether_mmc[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : - (*(u32 *)p); + if (j < OSD_INT_MAX) { + data[j++] = counter_helper(ether_mmc[i].sizeof_stat, p); + } } for (i = 0; i < ETHER_EXTRA_STAT_LEN; i++) { char *p = (char *)pdata + ether_gstrings_stats[i].stat_offset; - data[j++] = (ether_gstrings_stats[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + if (j < OSD_INT_MAX) { + data[j++] = counter_helper(ether_gstrings_stats[i].sizeof_stat, p); + } } #ifndef OSI_STRIPPED_LIB @@ -1096,16 +1113,18 @@ void ether_get_ethtool_stats(struct net_device *dev, char *p = (char *)osi_dma + ether_dstrings_stats[i].stat_offset; - data[j++] = (ether_dstrings_stats[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + if (j < OSD_INT_MAX) { + data[j++] = counter_helper(ether_dstrings_stats[i].sizeof_stat, p); + } } for (i = 0; i < ETHER_PKT_ERR_STAT_LEN; i++) { char *p = (char *)osi_dma + ether_cstrings_stats[i].stat_offset; - data[j++] = (ether_cstrings_stats[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + if (j < OSD_INT_MAX) { + data[j++] = counter_helper(ether_cstrings_stats[i].sizeof_stat, p); + } } for (i = 0; ((i < ETHER_FRP_STAT_LEN) && @@ -1113,8 +1132,9 @@ void ether_get_ethtool_stats(struct net_device *dev, char *p = (char *)osi_dma + ether_frpstrings_stats[i].stat_offset; - data[j++] = (ether_frpstrings_stats[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + if (j < OSD_INT_MAX) { + data[j++] = counter_helper(ether_frpstrings_stats[i].sizeof_stat, p); + } } #endif /* OSI_STRIPPED_LIB */ @@ -1122,8 +1142,9 @@ void ether_get_ethtool_stats(struct net_device *dev, char *p = (char *)osi_core + ether_tstrings_stats[i].stat_offset; - data[j++] = (ether_tstrings_stats[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + if (j < OSD_INT_MAX) { + data[j++] = counter_helper(ether_tstrings_stats[i].sizeof_stat, p); + } } } } @@ -1135,29 +1156,29 @@ int ether_get_sset_count(struct net_device *dev, int sset) if (sset == ETH_SS_STATS) { if (pdata->hw_feat.mmc_sel == OSI_ENABLE) { - if (INT_MAX < ETHER_MMC_STATS_LEN) { + if (OSD_INT_MAX < ETHER_MMC_STATS_LEN) { /* do nothing*/ } else { len = ETHER_MMC_STATS_LEN; } } - if (INT_MAX - ETHER_EXTRA_STAT_LEN < len) { + if (OSD_INT_MAX - ETHER_EXTRA_STAT_LEN < len) { /* do nothing */ } else { len += ETHER_EXTRA_STAT_LEN; } #ifndef OSI_STRIPPED_LIB - if (INT_MAX - ETHER_EXTRA_DMA_STAT_LEN < len) { + if (OSD_INT_MAX - ETHER_EXTRA_DMA_STAT_LEN < len) { /* do nothing */ } else { len += ETHER_EXTRA_DMA_STAT_LEN; } - if (INT_MAX - ETHER_PKT_ERR_STAT_LEN < len) { + if (OSD_INT_MAX - ETHER_PKT_ERR_STAT_LEN < len) { /* do nothing */ } else { len += ETHER_PKT_ERR_STAT_LEN; } - if (INT_MAX - ETHER_FRP_STAT_LEN < len) { + if (OSD_INT_MAX - ETHER_FRP_STAT_LEN < len) { /* do nothing */ } else { if (pdata->hw_feat.frp_sel == OSI_ENABLE) { @@ -1165,7 +1186,7 @@ int ether_get_sset_count(struct net_device *dev, int sset) } } #endif /* OSI_STRIPPED_LIB */ - if (INT_MAX - ETHER_CORE_STAT_LEN < len) { + if (OSD_INT_MAX - ETHER_CORE_STAT_LEN < len) { /* do nothing */ } else { len += ETHER_CORE_STAT_LEN; diff --git a/drivers/net/ethernet/nvidia/nvethernet/macsec.c b/drivers/net/ethernet/nvidia/nvethernet/macsec.c index 7e3787da..a050cc49 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/macsec.c +++ b/drivers/net/ethernet/nvidia/nvethernet/macsec.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2019-2024, NVIDIA CORPORATION. All rights reserved */ +// SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. #ifdef MACSEC_SUPPORT #include "ether_linux.h" @@ -420,7 +420,7 @@ static struct macsec_supplicant_data *macsec_get_supplicant( int i; /* check for already exist instance */ - for (i = 0; i < OSI_MAX_NUM_SC; i++) { + for (i = 0; i < OSI_MAX_NUM_SC_T26x; i++) { if (supplicant[i].snd_portid == portid && supplicant[i].in_use == OSI_ENABLE) { return &supplicant[i]; @@ -1052,6 +1052,7 @@ static int macsec_deinit(struct sk_buff *skb, struct genl_info *info) struct macsec_supplicant_data *supplicant; struct ether_priv_data *pdata; int ret = 0; + int ref_count_lcl = 0; PRINT_ENTRY(); @@ -1084,7 +1085,8 @@ static int macsec_deinit(struct sk_buff *skb, struct genl_info *info) macsec_pdata->next_supp_idx--; /* check for reference count to zero before deinit macsec */ - if ((atomic_read(&macsec_pdata->ref_count) - 1) > 0) { + ref_count_lcl = atomic_read(&macsec_pdata->ref_count); + if (ref_count_lcl > 1) { ret = 0; mutex_unlock(&macsec_pdata->lock); goto done; @@ -1309,7 +1311,7 @@ void macsec_remove(struct ether_priv_data *pdata) mutex_lock(&macsec_pdata->lock); /* Delete if any supplicant active heartbeat timer */ supplicant = macsec_pdata->supplicant; - for (i = 0; i < OSI_MAX_NUM_SC; i++) { + for (i = 0; i < OSI_MAX_NUM_SC_T26x; i++) { if (supplicant[i].in_use == OSI_ENABLE) { supplicant->snd_portid = OSI_NONE; supplicant->in_use = OSI_NONE; @@ -1473,6 +1475,8 @@ int macsec_probe(struct ether_priv_data *pdata) } else { strncpy(macsec_pdata->nv_macsec_fam.name, netdev_name(pdata->ndev), GENL_NAMSIZ - 1); + // Explicit null-termination to fix CERT STR07-C + macsec_pdata->nv_macsec_fam.name[GENL_NAMSIZ - 1] = '\0'; } ret = genl_register_family(&macsec_pdata->nv_macsec_fam); if (ret) { @@ -1671,6 +1675,8 @@ static int macsec_get_tx_next_pn(struct sk_buff *skb, struct genl_info *info) memset(&lut_config, OSI_NONE, sizeof(lut_config)); lut_config.table_config.ctlr_sel = OSI_CTLR_SEL_TX; lut_config.table_config.rw = OSI_LUT_READ; + // Added bitwise just to avoid CERT error + key_index = key_index & MAX_KEY_INDEX; lut_config.table_config.index = key_index + tx_sa.curr_an; lut_config.lut_sel = OSI_LUT_SEL_SA_STATE; if (osi_macsec_config_lut(osi_core, &lut_config) < 0) { diff --git a/drivers/net/ethernet/nvidia/nvethernet/macsec.h b/drivers/net/ethernet/nvidia/nvethernet/macsec.h index e52eedbd..cc3937d5 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/macsec.h +++ b/drivers/net/ethernet/nvidia/nvethernet/macsec.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2019-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved */ +/* Copyright (c) 2019-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved */ #ifndef INCLUDED_MACSEC_H #define INCLUDED_MACSEC_H @@ -40,6 +40,11 @@ */ #define MAX_SUPPLICANTS_ALLOWED 48 +/** + * @brief Maximum number of Key Indices for masking + */ +#define MAX_KEY_INDEX 0xFFU + #define NV_MACSEC_GENL_VERSION 1 #ifdef MACSEC_KEY_PROGRAM @@ -251,7 +256,7 @@ struct macsec_priv_data { /** MACsec controller init reference count */ atomic_t ref_count; /** supplicant instance specific data */ - struct macsec_supplicant_data supplicant[OSI_MAX_NUM_SC]; + struct macsec_supplicant_data supplicant[OSI_MAX_NUM_SC_T26x]; /** next supplicant instance index */ unsigned short next_supp_idx; /** macsec mutex lock */ diff --git a/drivers/net/ethernet/nvidia/nvethernet/osd.c b/drivers/net/ethernet/nvidia/nvethernet/osd.c index d55d4f1f..0b9dd82d 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/osd.c +++ b/drivers/net/ethernet/nvidia/nvethernet/osd.c @@ -33,6 +33,7 @@ static inline void add_skb_node(struct ether_priv_data *pdata, struct sk_buff *s unsigned int idx; unsigned long flags; unsigned long now_jiffies = jiffies; + unsigned long timeout_jiffies = msecs_to_jiffies(ETHER_SECTOMSEC); if (list_empty(&pdata->tx_ts_skb_head)) { goto empty; @@ -44,16 +45,17 @@ static inline void add_skb_node(struct ether_priv_data *pdata, struct sk_buff *s pnode = list_entry(head_node, struct ether_tx_ts_skb_list, list_head); - - if ((jiffies_to_msecs(now_jiffies) - jiffies_to_msecs(pnode->pkt_jiffies)) - >= ETHER_SECTOMSEC) { - dev_dbg(pdata->dev, "%s() skb %p deleting for pktid = %x time=%lu\n", - __func__, pnode->skb, pnode->pktid, pnode->pkt_jiffies); - if (pnode->skb != NULL) { - dev_consume_skb_any(pnode->skb); + if ((ULLONG_MAX - pnode->pkt_jiffies > timeout_jiffies) && + (now_jiffies > (pnode->pkt_jiffies + timeout_jiffies))) { + if (time_after_eq(now_jiffies, pnode->pkt_jiffies + timeout_jiffies)) { + dev_dbg(pdata->dev, "%s() skb %p deleting for pktid=%x time=%lu\n", + __func__, pnode->skb, pnode->pktid, pnode->pkt_jiffies); + if (pnode->skb != NULL) { + dev_consume_skb_any(pnode->skb); + } + list_del(head_node); + pnode->in_use = OSI_DISABLE; } - list_del(head_node); - pnode->in_use = OSI_DISABLE; } } raw_spin_unlock_irqrestore(&pdata->txts_lock, flags); @@ -671,7 +673,11 @@ void osd_receive_packet(void *priv, struct osi_rx_ring *rx_ring, skb_record_rx_queue(skb, chan); skb->dev = ndev; skb->protocol = eth_type_trans(skb, ndev); - ndev->stats.rx_bytes += skb->len; + if ((ULLONG_MAX - ndev->stats.rx_bytes) <= (skb->len)) { + ndev->stats.rx_bytes = skb->len; + } else { + ndev->stats.rx_bytes += skb->len; + } #ifdef ETHER_NVGRO if ((ndev->features & NETIF_F_GRO) && ether_do_nvgro(pdata, &rx_napi->napi, skb)) @@ -688,7 +694,11 @@ void osd_receive_packet(void *priv, struct osi_rx_ring *rx_ring, ndev->stats.rx_frame_errors = pkt_err_stat->rx_frame_error; #endif /* !OSI_STRIPPED_LIB */ ndev->stats.rx_fifo_errors = osi_core->mmc.mmc_rx_fifo_overflow; - ndev->stats.rx_errors++; + if (ndev->stats.rx_errors == ULLONG_MAX) { + ndev->stats.rx_errors = 0; + } else { + ndev->stats.rx_errors++; + } #ifdef ETHER_PAGE_POOL page_pool_recycle_direct(pdata->page_pool[chan], page); #endif @@ -698,7 +708,11 @@ void osd_receive_packet(void *priv, struct osi_rx_ring *rx_ring, #ifdef ETHER_NVGRO done: #endif - ndev->stats.rx_packets++; + if (ndev->stats.rx_packets == ULLONG_MAX) { + ndev->stats.rx_packets = 0; + } else { + ndev->stats.rx_packets++; + } rx_swcx->buf_virt_addr = NULL; rx_swcx->buf_phy_addr = 0; /* mark packet is processed */ @@ -723,7 +737,11 @@ void osd_transmit_complete(void *priv, const struct osi_tx_swcx *swcx, unsigned int chan, qinx; unsigned int len = swcx->len; - ndev->stats.tx_bytes += len; + if ((ULLONG_MAX - ndev->stats.tx_bytes) <= (len)) { + ndev->stats.tx_bytes = len; + } else { + ndev->stats.tx_bytes += len; + } #ifdef BW_TEST if (pdata->test_tx_bandwidth == OSI_ENABLE) { @@ -764,8 +782,11 @@ void osd_transmit_complete(void *priv, const struct osi_tx_swcx *swcx, netif_tx_wake_queue(txq); netdev_dbg(ndev, "Tx ring[%d] - waking Txq\n", chan); } - - ndev->stats.tx_packets++; + if (ndev->stats.tx_packets == ULLONG_MAX) { + ndev->stats.tx_packets = 0; + } else { + ndev->stats.tx_packets++; + } if ((txdone_pkt_cx->flags & OSI_TXDONE_CX_TS_DELAYED) == OSI_TXDONE_CX_TS_DELAYED) { add_skb_node(pdata, skb, txdone_pkt_cx->pktid, txdone_pkt_cx->vdmaid); @@ -936,6 +957,9 @@ int osd_ivc_send_cmd(void *priv, ivc_msg_common_t *ivc_buf, unsigned int len) return -1; } ivc_buf->status = -1; + if (cnt == (int)INT_MAX) { + cnt = 0; + } ivc_buf->count = cnt++; raw_spin_lock_irqsave(&ictxt->ivck_lock, flags); diff --git a/drivers/net/ethernet/nvidia/nvethernet/selftests.c b/drivers/net/ethernet/nvidia/nvethernet/selftests.c index ef34c928..8203b08d 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/selftests.c +++ b/drivers/net/ethernet/nvidia/nvethernet/selftests.c @@ -159,9 +159,9 @@ static int ether_test_loopback_validate(struct sk_buff *skb, #else unsigned char *dst = tpdata->ctxt->dst; #endif - struct ether_testhdr *thdr; - struct ethhdr *ehdr; - struct udphdr *uhdr; + struct ether_testhdr thdr; + struct ethhdr ehdr; + struct udphdr *uhdr, local_uhdr; struct iphdr *ihdr; skb = skb_unshare(skb, GFP_ATOMIC); @@ -173,9 +173,9 @@ static int ether_test_loopback_validate(struct sk_buff *skb, if (skb_headlen(skb) < (ETHER_TEST_PKT_SIZE - ETH_HLEN)) goto out; - ehdr = (struct ethhdr *)skb_mac_header(skb); + (void)memcpy(&ehdr, (void *)skb_mac_header(skb), sizeof(struct ethhdr)); if (dst) { - if (!ether_addr_equal_unaligned(ehdr->h_dest, dst)) + if (!ether_addr_equal_unaligned(ehdr.h_dest, dst)) goto out; } @@ -183,13 +183,14 @@ static int ether_test_loopback_validate(struct sk_buff *skb, if (ihdr->protocol != IPPROTO_UDP) goto out; - uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl); - if (uhdr->dest != htons(ETHER_UDP_TEST_PORT)) + (void)memcpy(&local_uhdr, (void *)((u8 *)ihdr + (4 * ihdr->ihl)), sizeof(local_uhdr)); + if (local_uhdr.dest != htons(ETHER_UDP_TEST_PORT)) goto out; - thdr = (struct ether_testhdr *)((u8 *)uhdr + sizeof(*uhdr)); + uhdr = (struct udphdr *)((u8 *)ihdr + (4 * ihdr->ihl)); + (void)memcpy(&thdr, (void *)((char *)uhdr + sizeof(*uhdr)), sizeof(thdr)); - if (thdr->magic != cpu_to_be64(ETHER_TEST_PKT_MAGIC)) + if (thdr.magic != cpu_to_be64(ETHER_TEST_PKT_MAGIC)) goto out; tpdata->completed = true; diff --git a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c index 3cc74c83..c33340f5 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c +++ b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include "ether_linux.h" #ifdef MACSEC_SUPPORT @@ -111,6 +111,12 @@ static inline int extract_mtu(const char* str) // Iterate through the string to find the first digit while (*str) { if (((*str) >= '0') && ((*str) <= '9')) { + // Adding boundary check + if ((num > (INT_MAX / 10)) || + ((num == (INT_MAX / 10)) && ((*str - '0') > (INT_MAX % 10)))) { + num = 0; + break; + } // Convert the digit characters to an integer num = num * 10 + (*str - '0'); } @@ -2974,19 +2980,26 @@ static ssize_t ether_mac_frp_show(struct device *dev, struct osi_core_priv_data *osi_core = pdata->osi_core; struct osi_core_frp_entry *entry = NULL; struct osi_core_frp_data *data = NULL; - int i = 0, j = 0; + int i = 0, j = 0, written = 0; /* Write FRP table entries */ for (i = 0, j = 0; ((i < osi_core->frp_cnt) && (j < PAGE_SIZE)); i++) { entry = &osi_core->frp_table[i]; data = &entry->data; - j += scnprintf((buf + j), (PAGE_SIZE - j), - "[%d] ID:%d MD:0x%x ME:0x%x AF:%d RF:%d IM:%d NIC:%d FO:%d OKI:%d DCH:x%llx\n", - i, entry->frp_id, data->match_data, - data->match_en, data->accept_frame, - data->reject_frame, data->inverse_match, - data->next_ins_ctrl, data->frame_offset, - data->ok_index, data->dma_chsel); + written = scnprintf((buf + j), (PAGE_SIZE - j), + "[%d] ID:%d MD:0x%x ME:0x%x AF:%d " + "RF:%d IM:%d NIC:%d FO:%d OKI:%d DCH:x%llx\n", + i, entry->frp_id, data->match_data, + data->match_en, data->accept_frame, + data->reject_frame, data->inverse_match, + data->next_ins_ctrl, data->frame_offset, + data->ok_index, data->dma_chsel); + //Ensure `written` is non-negative and within bounds + if ((written < 0) || (((unsigned long)j + (unsigned long)written) >= PAGE_SIZE)) { + // Prevent overflow and exit loop + break; + } + j += written; } return j;