virtchnl: fix fake 1-elem arrays for structures allocated as `nents`
authorAlexander Lobakin <aleksander.lobakin@intel.com>
Fri, 28 Jul 2023 15:52:07 +0000 (17:52 +0200)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Wed, 16 Aug 2023 16:14:14 +0000 (09:14 -0700)
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>
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/iavf/iavf_client.c
drivers/net/ethernet/intel/iavf/iavf_client.h
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
include/linux/avf/virtchnl.h

index a6983c2..8ea1a23 100644 (file)
@@ -506,6 +506,7 @@ i40e_config_rdma_qvlist(struct i40e_vf *vf,
        struct virtchnl_rdma_qv_info *qv_info;
        u32 v_idx, i, reg_idx, reg;
        u32 next_q_idx, next_q_type;
+       size_t size;
        u32 msix_vf;
        int ret = 0;
 
@@ -521,9 +522,9 @@ i40e_config_rdma_qvlist(struct i40e_vf *vf,
        }
 
        kfree(vf->qvlist_info);
-       vf->qvlist_info = kzalloc(struct_size(vf->qvlist_info, qv_info,
-                                             qvlist_info->num_vectors - 1),
-                                 GFP_KERNEL);
+       size = virtchnl_struct_size(vf->qvlist_info, qv_info,
+                                   qvlist_info->num_vectors);
+       vf->qvlist_info = kzalloc(size, GFP_KERNEL);
        if (!vf->qvlist_info) {
                ret = -ENOMEM;
                goto err_out;
index 93c903c..e6051b6 100644 (file)
@@ -469,8 +469,8 @@ static int iavf_client_setup_qvlist(struct iavf_info *ldev,
        }
 
        v_qvlist_info = (struct virtchnl_rdma_qvlist_info *)qvlist_info;
-       msg_size = struct_size(v_qvlist_info, qv_info,
-                              v_qvlist_info->num_vectors - 1);
+       msg_size = virtchnl_struct_size(v_qvlist_info, qv_info,
+                                       v_qvlist_info->num_vectors);
 
        adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP);
        err = iavf_aq_send_msg_to_pf(&adapter->hw,
index c5d51d7..500269b 100644 (file)
@@ -53,7 +53,7 @@ struct iavf_qv_info {
 
 struct iavf_qvlist_info {
        u32 num_vectors;
-       struct iavf_qv_info qv_info[1];
+       struct iavf_qv_info qv_info[];
 };
 
 #define IAVF_CLIENT_MSIX_ALL 0xFFFFFFFF
index 4fdac69..f9727e9 100644 (file)
@@ -727,15 +727,12 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                        more = true;
                }
 
-               len = sizeof(*vvfl_v2) + ((count - 1) *
-                                         sizeof(struct virtchnl_vlan_filter));
+               len = virtchnl_struct_size(vvfl_v2, filters, count);
                if (len > IAVF_MAX_AQ_BUF_SIZE) {
                        dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
-                       count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl_v2)) /
-                               sizeof(struct virtchnl_vlan_filter);
-                       len = sizeof(*vvfl_v2) +
-                               ((count - 1) *
-                                sizeof(struct virtchnl_vlan_filter));
+                       while (len > IAVF_MAX_AQ_BUF_SIZE)
+                               len = virtchnl_struct_size(vvfl_v2, filters,
+                                                          --count);
                        more = true;
                }
 
@@ -879,16 +876,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
 
                adapter->current_op = VIRTCHNL_OP_DEL_VLAN_V2;
 
-               len = sizeof(*vvfl_v2) +
-                       ((count - 1) * sizeof(struct virtchnl_vlan_filter));
+               len = virtchnl_struct_size(vvfl_v2, filters, count);
                if (len > IAVF_MAX_AQ_BUF_SIZE) {
                        dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
-                       count = (IAVF_MAX_AQ_BUF_SIZE -
-                                sizeof(*vvfl_v2)) /
-                               sizeof(struct virtchnl_vlan_filter);
-                       len = sizeof(*vvfl_v2) +
-                               ((count - 1) *
-                                sizeof(struct virtchnl_vlan_filter));
+                       while (len > IAVF_MAX_AQ_BUF_SIZE)
+                               len = virtchnl_struct_size(vvfl_v2, filters,
+                                                          --count);
                        more = true;
                }
 
@@ -1492,7 +1485,7 @@ void iavf_enable_channels(struct iavf_adapter *adapter)
                return;
        }
 
-       len = struct_size(vti, list, adapter->num_tc - 1);
+       len = virtchnl_struct_size(vti, list, adapter->num_tc);
        vti = kzalloc(len, GFP_KERNEL);
        if (!vti)
                return;
index c1a20b5..d0807ad 100644 (file)
@@ -716,10 +716,11 @@ struct virtchnl_vlan_filter_list_v2 {
        u16 vport_id;
        u16 num_elements;
        u8 pad[4];
-       struct virtchnl_vlan_filter filters[1];
+       struct virtchnl_vlan_filter filters[];
 };
 
-VIRTCHNL_CHECK_STRUCT_LEN(40, virtchnl_vlan_filter_list_v2);
+VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_vlan_filter_list_v2);
+#define virtchnl_vlan_filter_list_v2_LEGACY_SIZEOF     40
 
 /* VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2
  * VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2
@@ -918,10 +919,11 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_channel_info);
 struct virtchnl_tc_info {
        u32     num_tc;
        u32     pad;
-       struct  virtchnl_channel_info list[1];
+       struct virtchnl_channel_info list[];
 };
 
-VIRTCHNL_CHECK_STRUCT_LEN(24, virtchnl_tc_info);
+VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_tc_info);
+#define virtchnl_tc_info_LEGACY_SIZEOF 24
 
 /* VIRTCHNL_ADD_CLOUD_FILTER
  * VIRTCHNL_DEL_CLOUD_FILTER
@@ -1059,10 +1061,11 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_rdma_qv_info);
 
 struct virtchnl_rdma_qvlist_info {
        u32 num_vectors;
-       struct virtchnl_rdma_qv_info qv_info[1];
+       struct virtchnl_rdma_qv_info qv_info[];
 };
 
-VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_rdma_qvlist_info);
+VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_rdma_qvlist_info);
+#define virtchnl_rdma_qvlist_info_LEGACY_SIZEOF        16
 
 /* VF reset states - these are written into the RSTAT register:
  * VFGEN_RSTAT on the VF
@@ -1377,6 +1380,9 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_fdir_del);
 #define __vss_byone(p, member, count, old)                                   \
        (struct_size(p, member, count) + (old - 1 - struct_size(p, member, 0)))
 
+#define __vss_byelem(p, member, count, old)                                  \
+       (struct_size(p, member, count - 1) + (old - struct_size(p, member, 0)))
+
 #define __vss_full(p, member, count, old)                                    \
        (struct_size(p, member, count) + (old - struct_size(p, member, 0)))
 
@@ -1390,6 +1396,9 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_fdir_del);
                 __vss(virtchnl_irq_map_info, __vss_full, p, m, c),           \
                 __vss(virtchnl_ether_addr_list, __vss_full, p, m, c),        \
                 __vss(virtchnl_vlan_filter_list, __vss_full, p, m, c),       \
+                __vss(virtchnl_vlan_filter_list_v2, __vss_byelem, p, m, c),  \
+                __vss(virtchnl_tc_info, __vss_byelem, p, m, c),              \
+                __vss(virtchnl_rdma_qvlist_info, __vss_byelem, p, m, c),     \
                 __vss(virtchnl_rss_key, __vss_byone, p, m, c),               \
                 __vss(virtchnl_rss_lut, __vss_byone, p, m, c))
 
@@ -1495,13 +1504,13 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
        case VIRTCHNL_OP_RELEASE_RDMA_IRQ_MAP:
                break;
        case VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP:
-               valid_len = sizeof(struct virtchnl_rdma_qvlist_info);
+               valid_len = virtchnl_rdma_qvlist_info_LEGACY_SIZEOF;
                if (msglen >= valid_len) {
                        struct virtchnl_rdma_qvlist_info *qv =
                                (struct virtchnl_rdma_qvlist_info *)msg;
 
-                       valid_len += ((qv->num_vectors - 1) *
-                               sizeof(struct virtchnl_rdma_qv_info));
+                       valid_len = virtchnl_struct_size(qv, qv_info,
+                                                        qv->num_vectors);
                }
                break;
        case VIRTCHNL_OP_CONFIG_RSS_KEY:
@@ -1534,12 +1543,12 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
                valid_len = sizeof(struct virtchnl_vf_res_request);
                break;
        case VIRTCHNL_OP_ENABLE_CHANNELS:
-               valid_len = sizeof(struct virtchnl_tc_info);
+               valid_len = virtchnl_tc_info_LEGACY_SIZEOF;
                if (msglen >= valid_len) {
                        struct virtchnl_tc_info *vti =
                                (struct virtchnl_tc_info *)msg;
-                       valid_len += (vti->num_tc - 1) *
-                                    sizeof(struct virtchnl_channel_info);
+                       valid_len = virtchnl_struct_size(vti, list,
+                                                        vti->num_tc);
                        if (vti->num_tc == 0)
                                err_msg_format = true;
                }
@@ -1566,13 +1575,13 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
                break;
        case VIRTCHNL_OP_ADD_VLAN_V2:
        case VIRTCHNL_OP_DEL_VLAN_V2:
-               valid_len = sizeof(struct virtchnl_vlan_filter_list_v2);
+               valid_len = virtchnl_vlan_filter_list_v2_LEGACY_SIZEOF;
                if (msglen >= valid_len) {
                        struct virtchnl_vlan_filter_list_v2 *vfl =
                            (struct virtchnl_vlan_filter_list_v2 *)msg;
 
-                       valid_len += (vfl->num_elements - 1) *
-                               sizeof(struct virtchnl_vlan_filter);
+                       valid_len = virtchnl_struct_size(vfl, filters,
+                                                        vfl->num_elements);
 
                        if (vfl->num_elements == 0) {
                                err_msg_format = true;