Skip to content

Commit 5e7f59f

Browse files
alobakinanguy11
authored andcommitted
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 <[email protected]> Reviewed-by: Kees Cook <[email protected]> Tested-by: Rafal Romanowski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent dd2e84b commit 5e7f59f

File tree

5 files changed

+59
-52
lines changed

5 files changed

+59
-52
lines changed

drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
21032103
goto err;
21042104
}
21052105

2106-
len = struct_size(vfres, vsi_res, num_vsis);
2106+
len = virtchnl_struct_size(vfres, vsi_res, num_vsis);
21072107
vfres = kzalloc(len, GFP_KERNEL);
21082108
if (!vfres) {
21092109
aq_ret = -ENOMEM;

drivers/net/ethernet/intel/iavf/iavf.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ struct iavf_vsi {
9292
#define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */
9393
#define IAVF_MBPS_QUANTA 50
9494

95-
#define IAVF_VIRTCHNL_VF_RESOURCE_SIZE (sizeof(struct virtchnl_vf_resource) + \
96-
(IAVF_MAX_VF_VSI * \
97-
sizeof(struct virtchnl_vsi_resource)))
95+
#define IAVF_VIRTCHNL_VF_RESOURCE_SIZE \
96+
virtchnl_struct_size((struct virtchnl_vf_resource *)NULL, \
97+
vsi_res, IAVF_MAX_VF_VSI)
9898

9999
/* MAX_MSIX_Q_VECTORS of these are allocated,
100100
* but we only use one per queue-specific vector.

drivers/net/ethernet/intel/iavf/iavf_virtchnl.c

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter)
215215
u16 len;
216216
int err;
217217

218-
len = sizeof(struct virtchnl_vf_resource) +
219-
IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource);
218+
len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE;
220219
event.buf_len = len;
221220
event.msg_buf = kzalloc(len, GFP_KERNEL);
222221
if (!event.msg_buf)
@@ -284,7 +283,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
284283
return;
285284
}
286285
adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES;
287-
len = struct_size(vqci, qpair, pairs);
286+
len = virtchnl_struct_size(vqci, qpair, pairs);
288287
vqci = kzalloc(len, GFP_KERNEL);
289288
if (!vqci)
290289
return;
@@ -397,7 +396,7 @@ void iavf_map_queues(struct iavf_adapter *adapter)
397396

398397
q_vectors = adapter->num_msix_vectors - NONQ_VECS;
399398

400-
len = struct_size(vimi, vecmap, adapter->num_msix_vectors);
399+
len = virtchnl_struct_size(vimi, vecmap, adapter->num_msix_vectors);
401400
vimi = kzalloc(len, GFP_KERNEL);
402401
if (!vimi)
403402
return;
@@ -476,13 +475,11 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
476475
}
477476
adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR;
478477

479-
len = struct_size(veal, list, count);
478+
len = virtchnl_struct_size(veal, list, count);
480479
if (len > IAVF_MAX_AQ_BUF_SIZE) {
481480
dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n");
482-
count = (IAVF_MAX_AQ_BUF_SIZE -
483-
sizeof(struct virtchnl_ether_addr_list)) /
484-
sizeof(struct virtchnl_ether_addr);
485-
len = struct_size(veal, list, count);
481+
while (len > IAVF_MAX_AQ_BUF_SIZE)
482+
len = virtchnl_struct_size(veal, list, --count);
486483
more = true;
487484
}
488485

@@ -547,13 +544,11 @@ void iavf_del_ether_addrs(struct iavf_adapter *adapter)
547544
}
548545
adapter->current_op = VIRTCHNL_OP_DEL_ETH_ADDR;
549546

550-
len = struct_size(veal, list, count);
547+
len = virtchnl_struct_size(veal, list, count);
551548
if (len > IAVF_MAX_AQ_BUF_SIZE) {
552549
dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n");
553-
count = (IAVF_MAX_AQ_BUF_SIZE -
554-
sizeof(struct virtchnl_ether_addr_list)) /
555-
sizeof(struct virtchnl_ether_addr);
556-
len = struct_size(veal, list, count);
550+
while (len > IAVF_MAX_AQ_BUF_SIZE)
551+
len = virtchnl_struct_size(veal, list, --count);
557552
more = true;
558553
}
559554
veal = kzalloc(len, GFP_ATOMIC);
@@ -687,12 +682,12 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
687682

688683
adapter->current_op = VIRTCHNL_OP_ADD_VLAN;
689684

690-
len = sizeof(*vvfl) + (count * sizeof(u16));
685+
len = virtchnl_struct_size(vvfl, vlan_id, count);
691686
if (len > IAVF_MAX_AQ_BUF_SIZE) {
692687
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
693-
count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
694-
sizeof(u16);
695-
len = sizeof(*vvfl) + (count * sizeof(u16));
688+
while (len > IAVF_MAX_AQ_BUF_SIZE)
689+
len = virtchnl_struct_size(vvfl, vlan_id,
690+
--count);
696691
more = true;
697692
}
698693
vvfl = kzalloc(len, GFP_ATOMIC);
@@ -838,12 +833,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
838833

839834
adapter->current_op = VIRTCHNL_OP_DEL_VLAN;
840835

841-
len = sizeof(*vvfl) + (count * sizeof(u16));
836+
len = virtchnl_struct_size(vvfl, vlan_id, count);
842837
if (len > IAVF_MAX_AQ_BUF_SIZE) {
843838
dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
844-
count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
845-
sizeof(u16);
846-
len = sizeof(*vvfl) + (count * sizeof(u16));
839+
while (len > IAVF_MAX_AQ_BUF_SIZE)
840+
len = virtchnl_struct_size(vvfl, vlan_id,
841+
--count);
847842
more = true;
848843
}
849844
vvfl = kzalloc(len, GFP_ATOMIC);
@@ -2173,9 +2168,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
21732168
}
21742169
break;
21752170
case VIRTCHNL_OP_GET_VF_RESOURCES: {
2176-
u16 len = sizeof(struct virtchnl_vf_resource) +
2177-
IAVF_MAX_VF_VSI *
2178-
sizeof(struct virtchnl_vsi_resource);
2171+
u16 len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE;
2172+
21792173
memcpy(adapter->vf_res, msg, min(msglen, len));
21802174
iavf_validate_num_queues(adapter);
21812175
iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res);

drivers/net/ethernet/intel/ice/ice_virtchnl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
428428
goto err;
429429
}
430430

431-
len = sizeof(struct virtchnl_vf_resource);
431+
len = virtchnl_struct_size(vfres, vsi_res, 0);
432432

433433
vfres = kzalloc(len, GFP_KERNEL);
434434
if (!vfres) {

include/linux/avf/virtchnl.h

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,11 @@ struct virtchnl_vf_resource {
268268
u32 rss_key_size;
269269
u32 rss_lut_size;
270270

271-
struct virtchnl_vsi_resource vsi_res[1];
271+
struct virtchnl_vsi_resource vsi_res[];
272272
};
273273

274-
VIRTCHNL_CHECK_STRUCT_LEN(36, virtchnl_vf_resource);
274+
VIRTCHNL_CHECK_STRUCT_LEN(20, virtchnl_vf_resource);
275+
#define virtchnl_vf_resource_LEGACY_SIZEOF 36
275276

276277
/* VIRTCHNL_OP_CONFIG_TX_QUEUE
277278
* VF sends this message to set up parameters for one TX queue.
@@ -340,10 +341,11 @@ struct virtchnl_vsi_queue_config_info {
340341
u16 vsi_id;
341342
u16 num_queue_pairs;
342343
u32 pad;
343-
struct virtchnl_queue_pair_info qpair[1];
344+
struct virtchnl_queue_pair_info qpair[];
344345
};
345346

346-
VIRTCHNL_CHECK_STRUCT_LEN(72, virtchnl_vsi_queue_config_info);
347+
VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_vsi_queue_config_info);
348+
#define virtchnl_vsi_queue_config_info_LEGACY_SIZEOF 72
347349

348350
/* VIRTCHNL_OP_REQUEST_QUEUES
349351
* 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);
385387

386388
struct virtchnl_irq_map_info {
387389
u16 num_vectors;
388-
struct virtchnl_vector_map vecmap[1];
390+
struct virtchnl_vector_map vecmap[];
389391
};
390392

391-
VIRTCHNL_CHECK_STRUCT_LEN(14, virtchnl_irq_map_info);
393+
VIRTCHNL_CHECK_STRUCT_LEN(2, virtchnl_irq_map_info);
394+
#define virtchnl_irq_map_info_LEGACY_SIZEOF 14
392395

393396
/* VIRTCHNL_OP_ENABLE_QUEUES
394397
* VIRTCHNL_OP_DISABLE_QUEUES
@@ -459,10 +462,11 @@ VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_ether_addr);
459462
struct virtchnl_ether_addr_list {
460463
u16 vsi_id;
461464
u16 num_elements;
462-
struct virtchnl_ether_addr list[1];
465+
struct virtchnl_ether_addr list[];
463466
};
464467

465-
VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_ether_addr_list);
468+
VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_ether_addr_list);
469+
#define virtchnl_ether_addr_list_LEGACY_SIZEOF 12
466470

467471
/* VIRTCHNL_OP_ADD_VLAN
468472
* 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);
481485
struct virtchnl_vlan_filter_list {
482486
u16 vsi_id;
483487
u16 num_elements;
484-
u16 vlan_id[1];
488+
u16 vlan_id[];
485489
};
486490

487-
VIRTCHNL_CHECK_STRUCT_LEN(6, virtchnl_vlan_filter_list);
491+
VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_vlan_filter_list);
492+
#define virtchnl_vlan_filter_list_LEGACY_SIZEOF 6
488493

489494
/* This enum is used for all of the VIRTCHNL_VF_OFFLOAD_VLAN_V2_CAPS related
490495
* structures and opcodes.
@@ -1372,11 +1377,19 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_fdir_del);
13721377
#define __vss_byone(p, member, count, old) \
13731378
(struct_size(p, member, count) + (old - 1 - struct_size(p, member, 0)))
13741379

1380+
#define __vss_full(p, member, count, old) \
1381+
(struct_size(p, member, count) + (old - struct_size(p, member, 0)))
1382+
13751383
#define __vss(type, func, p, member, count) \
13761384
struct type: func(p, member, count, type##_LEGACY_SIZEOF)
13771385

13781386
#define virtchnl_struct_size(p, m, c) \
13791387
_Generic(*p, \
1388+
__vss(virtchnl_vf_resource, __vss_full, p, m, c), \
1389+
__vss(virtchnl_vsi_queue_config_info, __vss_full, p, m, c), \
1390+
__vss(virtchnl_irq_map_info, __vss_full, p, m, c), \
1391+
__vss(virtchnl_ether_addr_list, __vss_full, p, m, c), \
1392+
__vss(virtchnl_vlan_filter_list, __vss_full, p, m, c), \
13801393
__vss(virtchnl_rss_key, __vss_byone, p, m, c), \
13811394
__vss(virtchnl_rss_lut, __vss_byone, p, m, c))
13821395

@@ -1414,24 +1427,23 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
14141427
valid_len = sizeof(struct virtchnl_rxq_info);
14151428
break;
14161429
case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
1417-
valid_len = sizeof(struct virtchnl_vsi_queue_config_info);
1430+
valid_len = virtchnl_vsi_queue_config_info_LEGACY_SIZEOF;
14181431
if (msglen >= valid_len) {
14191432
struct virtchnl_vsi_queue_config_info *vqc =
14201433
(struct virtchnl_vsi_queue_config_info *)msg;
1421-
valid_len += (vqc->num_queue_pairs *
1422-
sizeof(struct
1423-
virtchnl_queue_pair_info));
1434+
valid_len = virtchnl_struct_size(vqc, qpair,
1435+
vqc->num_queue_pairs);
14241436
if (vqc->num_queue_pairs == 0)
14251437
err_msg_format = true;
14261438
}
14271439
break;
14281440
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
1429-
valid_len = sizeof(struct virtchnl_irq_map_info);
1441+
valid_len = virtchnl_irq_map_info_LEGACY_SIZEOF;
14301442
if (msglen >= valid_len) {
14311443
struct virtchnl_irq_map_info *vimi =
14321444
(struct virtchnl_irq_map_info *)msg;
1433-
valid_len += (vimi->num_vectors *
1434-
sizeof(struct virtchnl_vector_map));
1445+
valid_len = virtchnl_struct_size(vimi, vecmap,
1446+
vimi->num_vectors);
14351447
if (vimi->num_vectors == 0)
14361448
err_msg_format = true;
14371449
}
@@ -1442,23 +1454,24 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
14421454
break;
14431455
case VIRTCHNL_OP_ADD_ETH_ADDR:
14441456
case VIRTCHNL_OP_DEL_ETH_ADDR:
1445-
valid_len = sizeof(struct virtchnl_ether_addr_list);
1457+
valid_len = virtchnl_ether_addr_list_LEGACY_SIZEOF;
14461458
if (msglen >= valid_len) {
14471459
struct virtchnl_ether_addr_list *veal =
14481460
(struct virtchnl_ether_addr_list *)msg;
1449-
valid_len += veal->num_elements *
1450-
sizeof(struct virtchnl_ether_addr);
1461+
valid_len = virtchnl_struct_size(veal, list,
1462+
veal->num_elements);
14511463
if (veal->num_elements == 0)
14521464
err_msg_format = true;
14531465
}
14541466
break;
14551467
case VIRTCHNL_OP_ADD_VLAN:
14561468
case VIRTCHNL_OP_DEL_VLAN:
1457-
valid_len = sizeof(struct virtchnl_vlan_filter_list);
1469+
valid_len = virtchnl_vlan_filter_list_LEGACY_SIZEOF;
14581470
if (msglen >= valid_len) {
14591471
struct virtchnl_vlan_filter_list *vfl =
14601472
(struct virtchnl_vlan_filter_list *)msg;
1461-
valid_len += vfl->num_elements * sizeof(u16);
1473+
valid_len = virtchnl_struct_size(vfl, vlan_id,
1474+
vfl->num_elements);
14621475
if (vfl->num_elements == 0)
14631476
err_msg_format = true;
14641477
}

0 commit comments

Comments
 (0)