Commit 8dd7071f authored by David Arinzon's avatar David Arinzon Committed by Dong Chenchen
Browse files

net: ena: Add validation for completion descriptors consistency

mainline inclusion
from mainline-v6.10-rc1
commit b37b98a3a0c1198bafe8c2d9ce0bc845b4e7a9a7
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IACS9I
CVE: CVE-2024-40999

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b37b98a3a0c1198bafe8c2d9ce0bc845b4e7a9a7



--------------------------------

Validate that `first` flag is set only for the first
descriptor in multi-buffer packets.
In case of an invalid descriptor, a reset will occur.
A new reset reason for RX data corruption has been added.

Signed-off-by: default avatarShahar Itzko <itzko@amazon.com>
Signed-off-by: default avatarDavid Arinzon <darinzon@amazon.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20240512134637.25299-4-darinzon@amazon.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Conflicts:
	drivers/net/ethernet/amazon/ena/ena_eth_com.c
	drivers/net/ethernet/amazon/ena/ena_netdev.c
	drivers/net/ethernet/amazon/ena/ena_regs_defs.h
[commit 071271f39ce8 add ENA_REGS_RESET_SUSPECTED_POLL_STARVATION.
commit 09323b3b and 9fe890cc add ena_reset_device() and
ena_increase_stat() to refactor code, which lead to conflicts for
not merged.commit da580ca8 add device distinct log prefix to
files, which not merged. We can use pr_err().]
Signed-off-by: default avatarDong Chenchen <dongchenchen2@huawei.com>
parent 98dea376
Loading
Loading
Loading
Loading
+24 −11
Original line number Diff line number Diff line
@@ -222,42 +222,51 @@ static struct ena_eth_io_rx_cdesc_base *
		idx * io_cq->cdesc_entry_size_in_bytes);
}

static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
					   u16 *first_cdesc_idx)
static int ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
					u16 *first_cdesc_idx,
					u16 *num_descs)
{
	u16 count = io_cq->cur_rx_pkt_cdesc_count, head_masked;
	struct ena_eth_io_rx_cdesc_base *cdesc;
	u16 count = 0, head_masked;
	u32 last = 0;

	do {
		u32 status;

		cdesc = ena_com_get_next_rx_cdesc(io_cq);
		if (!cdesc)
			break;
		status = READ_ONCE(cdesc->status);

		ena_com_cq_inc_head(io_cq);
		if (unlikely((status & ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK) >>
		    ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT && count != 0)) {
			pr_err("First bit is on in descriptor #%d on q_id: %d, req_id: %u\n",
				count, io_cq->qid, cdesc->req_id);
			return -EFAULT;
		}
		count++;
		last = (READ_ONCE(cdesc->status) &
			ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >>
		last = (status & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >>
			ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT;
	} while (!last);

	if (last) {
		*first_cdesc_idx = io_cq->cur_rx_pkt_cdesc_start_idx;
		count += io_cq->cur_rx_pkt_cdesc_count;

		head_masked = io_cq->head & (io_cq->q_depth - 1);

		*num_descs = count;
		io_cq->cur_rx_pkt_cdesc_count = 0;
		io_cq->cur_rx_pkt_cdesc_start_idx = head_masked;

		pr_debug("ENA q_id: %d packets were completed. first desc idx %u descs# %d\n",
			 io_cq->qid, *first_cdesc_idx, count);
	} else {
		io_cq->cur_rx_pkt_cdesc_count += count;
		count = 0;
		io_cq->cur_rx_pkt_cdesc_count = count;
		*num_descs = 0;
	}

	return count;
	return 0;
}

static int ena_com_create_meta(struct ena_com_io_sq *io_sq,
@@ -517,10 +526,14 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
	u16 cdesc_idx = 0;
	u16 nb_hw_desc;
	u16 i = 0;
	int rc;

	WARN(io_cq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");

	nb_hw_desc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx);
	rc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx, &nb_hw_desc);
	if (unlikely(rc != 0))
		return -EFAULT;

	if (nb_hw_desc == 0) {
		ena_rx_ctx->descs = nb_hw_desc;
		return 0;
+2 −1
Original line number Diff line number Diff line
@@ -1687,6 +1687,8 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
		rx_ring->rx_stats.bad_desc_num++;
		u64_stats_update_end(&rx_ring->syncp);
		adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS;
	} else if (rc == -EFAULT) {
		adapter->reset_reason = ENA_REGS_RESET_RX_DESCRIPTOR_MALFORMED;
	} else {
		u64_stats_update_begin(&rx_ring->syncp);
		rx_ring->rx_stats.bad_req_id++;
@@ -4055,7 +4057,6 @@ static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
	pci_release_selected_regions(pdev, release_bars);
}


static int ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx)
{
	struct ena_admin_feature_llq_desc *llq = &ctx->get_feat_ctx->llq;
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ enum ena_regs_reset_reason_types {
	ENA_REGS_RESET_USER_TRIGGER                 = 12,
	ENA_REGS_RESET_GENERIC                      = 13,
	ENA_REGS_RESET_MISS_INTERRUPT               = 14,
	ENA_REGS_RESET_RX_DESCRIPTOR_MALFORMED	    = 15,
};

/* ena_registers offsets */