mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
virtchnl: fix fake 1-elem arrays in structures allocated as nents + 1
There are five virtchnl structures, which are allocated and checked in the code as `nents + 1`, meaning that they always have memory for one excessive element regardless of their actual number. This comes from that their sizeof() includes space for 1 element and then they get allocated via struct_size() or its open-coded equivalents, passing the actual number of elements. Expand virtchnl_struct_size() to handle such structures and replace those 1-elem arrays with proper flex ones. Also fix several places which open-code %IAVF_VIRTCHNL_VF_RESOURCE_SIZE. Finally, let the virtchnl_ether_addr_list size be computed automatically when there's no enough space for the whole list, otherwise we have to open-code reverse struct_size() logics. 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>
This commit is contained in:
committed by
Tony Nguyen
parent
dd2e84bb38
commit
5e7f59fa07
@@ -268,10 +268,11 @@ struct virtchnl_vf_resource {
|
||||
u32 rss_key_size;
|
||||
u32 rss_lut_size;
|
||||
|
||||
struct virtchnl_vsi_resource vsi_res[1];
|
||||
struct virtchnl_vsi_resource vsi_res[];
|
||||
};
|
||||
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(36, virtchnl_vf_resource);
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(20, virtchnl_vf_resource);
|
||||
#define virtchnl_vf_resource_LEGACY_SIZEOF 36
|
||||
|
||||
/* VIRTCHNL_OP_CONFIG_TX_QUEUE
|
||||
* VF sends this message to set up parameters for one TX queue.
|
||||
@@ -340,10 +341,11 @@ struct virtchnl_vsi_queue_config_info {
|
||||
u16 vsi_id;
|
||||
u16 num_queue_pairs;
|
||||
u32 pad;
|
||||
struct virtchnl_queue_pair_info qpair[1];
|
||||
struct virtchnl_queue_pair_info qpair[];
|
||||
};
|
||||
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(72, virtchnl_vsi_queue_config_info);
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_vsi_queue_config_info);
|
||||
#define virtchnl_vsi_queue_config_info_LEGACY_SIZEOF 72
|
||||
|
||||
/* VIRTCHNL_OP_REQUEST_QUEUES
|
||||
* VF sends this message to request the PF to allocate additional queues to
|
||||
@@ -385,10 +387,11 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_vector_map);
|
||||
|
||||
struct virtchnl_irq_map_info {
|
||||
u16 num_vectors;
|
||||
struct virtchnl_vector_map vecmap[1];
|
||||
struct virtchnl_vector_map vecmap[];
|
||||
};
|
||||
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(14, virtchnl_irq_map_info);
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(2, virtchnl_irq_map_info);
|
||||
#define virtchnl_irq_map_info_LEGACY_SIZEOF 14
|
||||
|
||||
/* VIRTCHNL_OP_ENABLE_QUEUES
|
||||
* VIRTCHNL_OP_DISABLE_QUEUES
|
||||
@@ -459,10 +462,11 @@ VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_ether_addr);
|
||||
struct virtchnl_ether_addr_list {
|
||||
u16 vsi_id;
|
||||
u16 num_elements;
|
||||
struct virtchnl_ether_addr list[1];
|
||||
struct virtchnl_ether_addr list[];
|
||||
};
|
||||
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_ether_addr_list);
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_ether_addr_list);
|
||||
#define virtchnl_ether_addr_list_LEGACY_SIZEOF 12
|
||||
|
||||
/* VIRTCHNL_OP_ADD_VLAN
|
||||
* VF sends this message to add one or more VLAN tag filters for receives.
|
||||
@@ -481,10 +485,11 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_ether_addr_list);
|
||||
struct virtchnl_vlan_filter_list {
|
||||
u16 vsi_id;
|
||||
u16 num_elements;
|
||||
u16 vlan_id[1];
|
||||
u16 vlan_id[];
|
||||
};
|
||||
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(6, virtchnl_vlan_filter_list);
|
||||
VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_vlan_filter_list);
|
||||
#define virtchnl_vlan_filter_list_LEGACY_SIZEOF 6
|
||||
|
||||
/* This enum is used for all of the VIRTCHNL_VF_OFFLOAD_VLAN_V2_CAPS related
|
||||
* structures and opcodes.
|
||||
@@ -1372,11 +1377,19 @@ 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_full(p, member, count, old) \
|
||||
(struct_size(p, member, count) + (old - struct_size(p, member, 0)))
|
||||
|
||||
#define __vss(type, func, p, member, count) \
|
||||
struct type: func(p, member, count, type##_LEGACY_SIZEOF)
|
||||
|
||||
#define virtchnl_struct_size(p, m, c) \
|
||||
_Generic(*p, \
|
||||
__vss(virtchnl_vf_resource, __vss_full, p, m, c), \
|
||||
__vss(virtchnl_vsi_queue_config_info, __vss_full, p, m, c), \
|
||||
__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_rss_key, __vss_byone, p, m, c), \
|
||||
__vss(virtchnl_rss_lut, __vss_byone, p, m, c))
|
||||
|
||||
@@ -1414,24 +1427,23 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
|
||||
valid_len = sizeof(struct virtchnl_rxq_info);
|
||||
break;
|
||||
case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
|
||||
valid_len = sizeof(struct virtchnl_vsi_queue_config_info);
|
||||
valid_len = virtchnl_vsi_queue_config_info_LEGACY_SIZEOF;
|
||||
if (msglen >= valid_len) {
|
||||
struct virtchnl_vsi_queue_config_info *vqc =
|
||||
(struct virtchnl_vsi_queue_config_info *)msg;
|
||||
valid_len += (vqc->num_queue_pairs *
|
||||
sizeof(struct
|
||||
virtchnl_queue_pair_info));
|
||||
valid_len = virtchnl_struct_size(vqc, qpair,
|
||||
vqc->num_queue_pairs);
|
||||
if (vqc->num_queue_pairs == 0)
|
||||
err_msg_format = true;
|
||||
}
|
||||
break;
|
||||
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
|
||||
valid_len = sizeof(struct virtchnl_irq_map_info);
|
||||
valid_len = virtchnl_irq_map_info_LEGACY_SIZEOF;
|
||||
if (msglen >= valid_len) {
|
||||
struct virtchnl_irq_map_info *vimi =
|
||||
(struct virtchnl_irq_map_info *)msg;
|
||||
valid_len += (vimi->num_vectors *
|
||||
sizeof(struct virtchnl_vector_map));
|
||||
valid_len = virtchnl_struct_size(vimi, vecmap,
|
||||
vimi->num_vectors);
|
||||
if (vimi->num_vectors == 0)
|
||||
err_msg_format = true;
|
||||
}
|
||||
@@ -1442,23 +1454,24 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
|
||||
break;
|
||||
case VIRTCHNL_OP_ADD_ETH_ADDR:
|
||||
case VIRTCHNL_OP_DEL_ETH_ADDR:
|
||||
valid_len = sizeof(struct virtchnl_ether_addr_list);
|
||||
valid_len = virtchnl_ether_addr_list_LEGACY_SIZEOF;
|
||||
if (msglen >= valid_len) {
|
||||
struct virtchnl_ether_addr_list *veal =
|
||||
(struct virtchnl_ether_addr_list *)msg;
|
||||
valid_len += veal->num_elements *
|
||||
sizeof(struct virtchnl_ether_addr);
|
||||
valid_len = virtchnl_struct_size(veal, list,
|
||||
veal->num_elements);
|
||||
if (veal->num_elements == 0)
|
||||
err_msg_format = true;
|
||||
}
|
||||
break;
|
||||
case VIRTCHNL_OP_ADD_VLAN:
|
||||
case VIRTCHNL_OP_DEL_VLAN:
|
||||
valid_len = sizeof(struct virtchnl_vlan_filter_list);
|
||||
valid_len = virtchnl_vlan_filter_list_LEGACY_SIZEOF;
|
||||
if (msglen >= valid_len) {
|
||||
struct virtchnl_vlan_filter_list *vfl =
|
||||
(struct virtchnl_vlan_filter_list *)msg;
|
||||
valid_len += vfl->num_elements * sizeof(u16);
|
||||
valid_len = virtchnl_struct_size(vfl, vlan_id,
|
||||
vfl->num_elements);
|
||||
if (vfl->num_elements == 0)
|
||||
err_msg_format = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user