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

virtchnl: fix fake 1-elem arrays for structures allocated as `nents`

Finally, fix 3 structures which are allocated technically correctly,
i.e. the calculated size equals to the one that struct_size() would
return, except for sizeof(). For &virtchnl_vlan_filter_list_v2, use
the same approach when there are no enough space as taken previously
for &virtchnl_vlan_filter_list, i.e. let the maximum size be calculated
automatically instead of trying to guestimate it using maths.

Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>

authored by

Alexander Lobakin and committed by
Tony Nguyen
b0654e64 5e7f59fa

+40 -37
+4 -3
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
··· 506 506 struct virtchnl_rdma_qv_info *qv_info; 507 507 u32 v_idx, i, reg_idx, reg; 508 508 u32 next_q_idx, next_q_type; 509 + size_t size; 509 510 u32 msix_vf; 510 511 int ret = 0; 511 512 ··· 522 521 } 523 522 524 523 kfree(vf->qvlist_info); 525 - vf->qvlist_info = kzalloc(struct_size(vf->qvlist_info, qv_info, 526 - qvlist_info->num_vectors - 1), 527 - GFP_KERNEL); 524 + size = virtchnl_struct_size(vf->qvlist_info, qv_info, 525 + qvlist_info->num_vectors); 526 + vf->qvlist_info = kzalloc(size, GFP_KERNEL); 528 527 if (!vf->qvlist_info) { 529 528 ret = -ENOMEM; 530 529 goto err_out;
+2 -2
drivers/net/ethernet/intel/iavf/iavf_client.c
··· 469 469 } 470 470 471 471 v_qvlist_info = (struct virtchnl_rdma_qvlist_info *)qvlist_info; 472 - msg_size = struct_size(v_qvlist_info, qv_info, 473 - v_qvlist_info->num_vectors - 1); 472 + msg_size = virtchnl_struct_size(v_qvlist_info, qv_info, 473 + v_qvlist_info->num_vectors); 474 474 475 475 adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP); 476 476 err = iavf_aq_send_msg_to_pf(&adapter->hw,
+1 -1
drivers/net/ethernet/intel/iavf/iavf_client.h
··· 53 53 54 54 struct iavf_qvlist_info { 55 55 u32 num_vectors; 56 - struct iavf_qv_info qv_info[1]; 56 + struct iavf_qv_info qv_info[]; 57 57 }; 58 58 59 59 #define IAVF_CLIENT_MSIX_ALL 0xFFFFFFFF
+9 -16
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
··· 727 727 more = true; 728 728 } 729 729 730 - len = sizeof(*vvfl_v2) + ((count - 1) * 731 - sizeof(struct virtchnl_vlan_filter)); 730 + len = virtchnl_struct_size(vvfl_v2, filters, count); 732 731 if (len > IAVF_MAX_AQ_BUF_SIZE) { 733 732 dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); 734 - count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl_v2)) / 735 - sizeof(struct virtchnl_vlan_filter); 736 - len = sizeof(*vvfl_v2) + 737 - ((count - 1) * 738 - sizeof(struct virtchnl_vlan_filter)); 733 + while (len > IAVF_MAX_AQ_BUF_SIZE) 734 + len = virtchnl_struct_size(vvfl_v2, filters, 735 + --count); 739 736 more = true; 740 737 } 741 738 ··· 876 879 877 880 adapter->current_op = VIRTCHNL_OP_DEL_VLAN_V2; 878 881 879 - len = sizeof(*vvfl_v2) + 880 - ((count - 1) * sizeof(struct virtchnl_vlan_filter)); 882 + len = virtchnl_struct_size(vvfl_v2, filters, count); 881 883 if (len > IAVF_MAX_AQ_BUF_SIZE) { 882 884 dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); 883 - count = (IAVF_MAX_AQ_BUF_SIZE - 884 - sizeof(*vvfl_v2)) / 885 - sizeof(struct virtchnl_vlan_filter); 886 - len = sizeof(*vvfl_v2) + 887 - ((count - 1) * 888 - sizeof(struct virtchnl_vlan_filter)); 885 + while (len > IAVF_MAX_AQ_BUF_SIZE) 886 + len = virtchnl_struct_size(vvfl_v2, filters, 887 + --count); 889 888 more = true; 890 889 } 891 890 ··· 1485 1492 return; 1486 1493 } 1487 1494 1488 - len = struct_size(vti, list, adapter->num_tc - 1); 1495 + len = virtchnl_struct_size(vti, list, adapter->num_tc); 1489 1496 vti = kzalloc(len, GFP_KERNEL); 1490 1497 if (!vti) 1491 1498 return;
+24 -15
include/linux/avf/virtchnl.h
··· 716 716 u16 vport_id; 717 717 u16 num_elements; 718 718 u8 pad[4]; 719 - struct virtchnl_vlan_filter filters[1]; 719 + struct virtchnl_vlan_filter filters[]; 720 720 }; 721 721 722 - VIRTCHNL_CHECK_STRUCT_LEN(40, virtchnl_vlan_filter_list_v2); 722 + VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_vlan_filter_list_v2); 723 + #define virtchnl_vlan_filter_list_v2_LEGACY_SIZEOF 40 723 724 724 725 /* VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 725 726 * VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2 ··· 919 918 struct virtchnl_tc_info { 920 919 u32 num_tc; 921 920 u32 pad; 922 - struct virtchnl_channel_info list[1]; 921 + struct virtchnl_channel_info list[]; 923 922 }; 924 923 925 - VIRTCHNL_CHECK_STRUCT_LEN(24, virtchnl_tc_info); 924 + VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_tc_info); 925 + #define virtchnl_tc_info_LEGACY_SIZEOF 24 926 926 927 927 /* VIRTCHNL_ADD_CLOUD_FILTER 928 928 * VIRTCHNL_DEL_CLOUD_FILTER ··· 1061 1059 1062 1060 struct virtchnl_rdma_qvlist_info { 1063 1061 u32 num_vectors; 1064 - struct virtchnl_rdma_qv_info qv_info[1]; 1062 + struct virtchnl_rdma_qv_info qv_info[]; 1065 1063 }; 1066 1064 1067 - VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_rdma_qvlist_info); 1065 + VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_rdma_qvlist_info); 1066 + #define virtchnl_rdma_qvlist_info_LEGACY_SIZEOF 16 1068 1067 1069 1068 /* VF reset states - these are written into the RSTAT register: 1070 1069 * VFGEN_RSTAT on the VF ··· 1380 1377 #define __vss_byone(p, member, count, old) \ 1381 1378 (struct_size(p, member, count) + (old - 1 - struct_size(p, member, 0))) 1382 1379 1380 + #define __vss_byelem(p, member, count, old) \ 1381 + (struct_size(p, member, count - 1) + (old - struct_size(p, member, 0))) 1382 + 1383 1383 #define __vss_full(p, member, count, old) \ 1384 1384 (struct_size(p, member, count) + (old - struct_size(p, member, 0))) 1385 1385 ··· 1396 1390 __vss(virtchnl_irq_map_info, __vss_full, p, m, c), \ 1397 1391 __vss(virtchnl_ether_addr_list, __vss_full, p, m, c), \ 1398 1392 __vss(virtchnl_vlan_filter_list, __vss_full, p, m, c), \ 1393 + __vss(virtchnl_vlan_filter_list_v2, __vss_byelem, p, m, c), \ 1394 + __vss(virtchnl_tc_info, __vss_byelem, p, m, c), \ 1395 + __vss(virtchnl_rdma_qvlist_info, __vss_byelem, p, m, c), \ 1399 1396 __vss(virtchnl_rss_key, __vss_byone, p, m, c), \ 1400 1397 __vss(virtchnl_rss_lut, __vss_byone, p, m, c)) 1401 1398 ··· 1504 1495 case VIRTCHNL_OP_RELEASE_RDMA_IRQ_MAP: 1505 1496 break; 1506 1497 case VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP: 1507 - valid_len = sizeof(struct virtchnl_rdma_qvlist_info); 1498 + valid_len = virtchnl_rdma_qvlist_info_LEGACY_SIZEOF; 1508 1499 if (msglen >= valid_len) { 1509 1500 struct virtchnl_rdma_qvlist_info *qv = 1510 1501 (struct virtchnl_rdma_qvlist_info *)msg; 1511 1502 1512 - valid_len += ((qv->num_vectors - 1) * 1513 - sizeof(struct virtchnl_rdma_qv_info)); 1503 + valid_len = virtchnl_struct_size(qv, qv_info, 1504 + qv->num_vectors); 1514 1505 } 1515 1506 break; 1516 1507 case VIRTCHNL_OP_CONFIG_RSS_KEY: ··· 1543 1534 valid_len = sizeof(struct virtchnl_vf_res_request); 1544 1535 break; 1545 1536 case VIRTCHNL_OP_ENABLE_CHANNELS: 1546 - valid_len = sizeof(struct virtchnl_tc_info); 1537 + valid_len = virtchnl_tc_info_LEGACY_SIZEOF; 1547 1538 if (msglen >= valid_len) { 1548 1539 struct virtchnl_tc_info *vti = 1549 1540 (struct virtchnl_tc_info *)msg; 1550 - valid_len += (vti->num_tc - 1) * 1551 - sizeof(struct virtchnl_channel_info); 1541 + valid_len = virtchnl_struct_size(vti, list, 1542 + vti->num_tc); 1552 1543 if (vti->num_tc == 0) 1553 1544 err_msg_format = true; 1554 1545 } ··· 1575 1566 break; 1576 1567 case VIRTCHNL_OP_ADD_VLAN_V2: 1577 1568 case VIRTCHNL_OP_DEL_VLAN_V2: 1578 - valid_len = sizeof(struct virtchnl_vlan_filter_list_v2); 1569 + valid_len = virtchnl_vlan_filter_list_v2_LEGACY_SIZEOF; 1579 1570 if (msglen >= valid_len) { 1580 1571 struct virtchnl_vlan_filter_list_v2 *vfl = 1581 1572 (struct virtchnl_vlan_filter_list_v2 *)msg; 1582 1573 1583 - valid_len += (vfl->num_elements - 1) * 1584 - sizeof(struct virtchnl_vlan_filter); 1574 + valid_len = virtchnl_struct_size(vfl, filters, 1575 + vfl->num_elements); 1585 1576 1586 1577 if (vfl->num_elements == 0) { 1587 1578 err_msg_format = true;