From: Junrui Luo The VF allocates a fixed-size buffer for IAVF_MAX_VF_VSI (3) VSI entries when processing a VIRTCHNL_OP_GET_VF_RESOURCES response from the PF. However, num_vsis from the PF response is used unchecked as the loop bound when iterating over vsi_res[] in multiple functions. A PF sending num_vsis greater than IAVF_MAX_VF_VSI, or the received message is shorter than num_vsis claims leads to out-of-bounds accesses on the vsi_res[] array. Clamp num_vsis based on the actual bytes copied from the PF response. Fixes: 5eae00c57f5e ("i40evf: main driver core") Reported-by: Yuhao Jiang Cc: stable@vger.kernel.org Signed-off-by: Junrui Luo Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index ec234cc8bd9d..c4039d2b24a4 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -248,12 +248,28 @@ int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter) /** * iavf_validate_num_queues * @adapter: adapter structure + * @msglen: length of the received VF resource message * - * Validate that the number of queues the PF has sent in - * VIRTCHNL_OP_GET_VF_RESOURCES is not larger than the VF can handle. + * Validate the VIRTCHNL_OP_GET_VF_RESOURCES response from the PF. Ensure + * num_vsis does not exceed what the message length can cover, and cap + * num_queue_pairs to the VF maximum. **/ -static void iavf_validate_num_queues(struct iavf_adapter *adapter) +static void iavf_validate_num_queues(struct iavf_adapter *adapter, u16 msglen) { + u16 max_vsis; + + if (msglen < sizeof(struct virtchnl_vf_resource)) + max_vsis = 0; + else + max_vsis = (msglen - sizeof(struct virtchnl_vf_resource)) / + sizeof(struct virtchnl_vsi_resource); + + if (adapter->vf_res->num_vsis > max_vsis) { + dev_info(&adapter->pdev->dev, "Received %d VSIs, but message can only cover %d\n", + adapter->vf_res->num_vsis, max_vsis); + adapter->vf_res->num_vsis = max_vsis; + } + if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) { struct virtchnl_vsi_resource *vsi_res; int i; @@ -300,7 +316,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter) * we aren't getting too many queues */ if (!err) - iavf_validate_num_queues(adapter); + iavf_validate_num_queues(adapter, min(event.msg_len, len)); iavf_vf_parse_hw_config(hw, adapter->vf_res); kfree(event.msg_buf); @@ -2578,7 +2594,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, u16 len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE; memcpy(adapter->vf_res, msg, min(msglen, len)); - iavf_validate_num_queues(adapter); + iavf_validate_num_queues(adapter, min(msglen, len)); iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res); if (is_zero_ether_addr(adapter->hw.mac.addr)) { /* restore current mac address */ -- 2.47.1