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 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>

authored by

Alexander Lobakin and committed by
Tony Nguyen
5e7f59fa dd2e84bb

+59 -52
+1 -1
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
··· 2103 2103 goto err; 2104 2104 } 2105 2105 2106 - len = struct_size(vfres, vsi_res, num_vsis); 2106 + len = virtchnl_struct_size(vfres, vsi_res, num_vsis); 2107 2107 vfres = kzalloc(len, GFP_KERNEL); 2108 2108 if (!vfres) { 2109 2109 aq_ret = -ENOMEM;
+3 -3
drivers/net/ethernet/intel/iavf/iavf.h
··· 92 92 #define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */ 93 93 #define IAVF_MBPS_QUANTA 50 94 94 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) 98 98 99 99 /* MAX_MSIX_Q_VECTORS of these are allocated, 100 100 * but we only use one per queue-specific vector.
+19 -25
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
··· 215 215 u16 len; 216 216 int err; 217 217 218 - len = sizeof(struct virtchnl_vf_resource) + 219 - IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); 218 + len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE; 220 219 event.buf_len = len; 221 220 event.msg_buf = kzalloc(len, GFP_KERNEL); 222 221 if (!event.msg_buf) ··· 283 284 return; 284 285 } 285 286 adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES; 286 - len = struct_size(vqci, qpair, pairs); 287 + len = virtchnl_struct_size(vqci, qpair, pairs); 287 288 vqci = kzalloc(len, GFP_KERNEL); 288 289 if (!vqci) 289 290 return; ··· 396 397 397 398 q_vectors = adapter->num_msix_vectors - NONQ_VECS; 398 399 399 - len = struct_size(vimi, vecmap, adapter->num_msix_vectors); 400 + len = virtchnl_struct_size(vimi, vecmap, adapter->num_msix_vectors); 400 401 vimi = kzalloc(len, GFP_KERNEL); 401 402 if (!vimi) 402 403 return; ··· 475 476 } 476 477 adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR; 477 478 478 - len = struct_size(veal, list, count); 479 + len = virtchnl_struct_size(veal, list, count); 479 480 if (len > IAVF_MAX_AQ_BUF_SIZE) { 480 481 dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n"); 481 - count = (IAVF_MAX_AQ_BUF_SIZE - 482 - sizeof(struct virtchnl_ether_addr_list)) / 483 - sizeof(struct virtchnl_ether_addr); 484 - len = struct_size(veal, list, count); 482 + while (len > IAVF_MAX_AQ_BUF_SIZE) 483 + len = virtchnl_struct_size(veal, list, --count); 485 484 more = true; 486 485 } 487 486 ··· 544 547 } 545 548 adapter->current_op = VIRTCHNL_OP_DEL_ETH_ADDR; 546 549 547 - len = struct_size(veal, list, count); 550 + len = virtchnl_struct_size(veal, list, count); 548 551 if (len > IAVF_MAX_AQ_BUF_SIZE) { 549 552 dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n"); 550 - count = (IAVF_MAX_AQ_BUF_SIZE - 551 - sizeof(struct virtchnl_ether_addr_list)) / 552 - sizeof(struct virtchnl_ether_addr); 553 - len = struct_size(veal, list, count); 553 + while (len > IAVF_MAX_AQ_BUF_SIZE) 554 + len = virtchnl_struct_size(veal, list, --count); 554 555 more = true; 555 556 } 556 557 veal = kzalloc(len, GFP_ATOMIC); ··· 682 687 683 688 adapter->current_op = VIRTCHNL_OP_ADD_VLAN; 684 689 685 - len = sizeof(*vvfl) + (count * sizeof(u16)); 690 + len = virtchnl_struct_size(vvfl, vlan_id, count); 686 691 if (len > IAVF_MAX_AQ_BUF_SIZE) { 687 692 dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); 688 - count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) / 689 - sizeof(u16); 690 - len = sizeof(*vvfl) + (count * sizeof(u16)); 693 + while (len > IAVF_MAX_AQ_BUF_SIZE) 694 + len = virtchnl_struct_size(vvfl, vlan_id, 695 + --count); 691 696 more = true; 692 697 } 693 698 vvfl = kzalloc(len, GFP_ATOMIC); ··· 833 838 834 839 adapter->current_op = VIRTCHNL_OP_DEL_VLAN; 835 840 836 - len = sizeof(*vvfl) + (count * sizeof(u16)); 841 + len = virtchnl_struct_size(vvfl, vlan_id, count); 837 842 if (len > IAVF_MAX_AQ_BUF_SIZE) { 838 843 dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n"); 839 - count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) / 840 - sizeof(u16); 841 - len = sizeof(*vvfl) + (count * sizeof(u16)); 844 + while (len > IAVF_MAX_AQ_BUF_SIZE) 845 + len = virtchnl_struct_size(vvfl, vlan_id, 846 + --count); 842 847 more = true; 843 848 } 844 849 vvfl = kzalloc(len, GFP_ATOMIC); ··· 2168 2173 } 2169 2174 break; 2170 2175 case VIRTCHNL_OP_GET_VF_RESOURCES: { 2171 - u16 len = sizeof(struct virtchnl_vf_resource) + 2172 - IAVF_MAX_VF_VSI * 2173 - sizeof(struct virtchnl_vsi_resource); 2176 + u16 len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE; 2177 + 2174 2178 memcpy(adapter->vf_res, msg, min(msglen, len)); 2175 2179 iavf_validate_num_queues(adapter); 2176 2180 iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res);
+1 -1
drivers/net/ethernet/intel/ice/ice_virtchnl.c
··· 428 428 goto err; 429 429 } 430 430 431 - len = sizeof(struct virtchnl_vf_resource); 431 + len = virtchnl_struct_size(vfres, vsi_res, 0); 432 432 433 433 vfres = kzalloc(len, GFP_KERNEL); 434 434 if (!vfres) {
+35 -22
include/linux/avf/virtchnl.h
··· 268 268 u32 rss_key_size; 269 269 u32 rss_lut_size; 270 270 271 - struct virtchnl_vsi_resource vsi_res[1]; 271 + struct virtchnl_vsi_resource vsi_res[]; 272 272 }; 273 273 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 275 276 276 277 /* VIRTCHNL_OP_CONFIG_TX_QUEUE 277 278 * VF sends this message to set up parameters for one TX queue. ··· 341 340 u16 vsi_id; 342 341 u16 num_queue_pairs; 343 342 u32 pad; 344 - struct virtchnl_queue_pair_info qpair[1]; 343 + struct virtchnl_queue_pair_info qpair[]; 345 344 }; 346 345 347 - VIRTCHNL_CHECK_STRUCT_LEN(72, virtchnl_vsi_queue_config_info); 346 + VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_vsi_queue_config_info); 347 + #define virtchnl_vsi_queue_config_info_LEGACY_SIZEOF 72 348 348 349 349 /* VIRTCHNL_OP_REQUEST_QUEUES 350 350 * VF sends this message to request the PF to allocate additional queues to ··· 387 385 388 386 struct virtchnl_irq_map_info { 389 387 u16 num_vectors; 390 - struct virtchnl_vector_map vecmap[1]; 388 + struct virtchnl_vector_map vecmap[]; 391 389 }; 392 390 393 - VIRTCHNL_CHECK_STRUCT_LEN(14, virtchnl_irq_map_info); 391 + VIRTCHNL_CHECK_STRUCT_LEN(2, virtchnl_irq_map_info); 392 + #define virtchnl_irq_map_info_LEGACY_SIZEOF 14 394 393 395 394 /* VIRTCHNL_OP_ENABLE_QUEUES 396 395 * VIRTCHNL_OP_DISABLE_QUEUES ··· 462 459 struct virtchnl_ether_addr_list { 463 460 u16 vsi_id; 464 461 u16 num_elements; 465 - struct virtchnl_ether_addr list[1]; 462 + struct virtchnl_ether_addr list[]; 466 463 }; 467 464 468 - VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_ether_addr_list); 465 + VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_ether_addr_list); 466 + #define virtchnl_ether_addr_list_LEGACY_SIZEOF 12 469 467 470 468 /* VIRTCHNL_OP_ADD_VLAN 471 469 * VF sends this message to add one or more VLAN tag filters for receives. ··· 485 481 struct virtchnl_vlan_filter_list { 486 482 u16 vsi_id; 487 483 u16 num_elements; 488 - u16 vlan_id[1]; 484 + u16 vlan_id[]; 489 485 }; 490 486 491 - VIRTCHNL_CHECK_STRUCT_LEN(6, virtchnl_vlan_filter_list); 487 + VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_vlan_filter_list); 488 + #define virtchnl_vlan_filter_list_LEGACY_SIZEOF 6 492 489 493 490 /* This enum is used for all of the VIRTCHNL_VF_OFFLOAD_VLAN_V2_CAPS related 494 491 * structures and opcodes. ··· 1377 1372 #define __vss_byone(p, member, count, old) \ 1378 1373 (struct_size(p, member, count) + (old - 1 - struct_size(p, member, 0))) 1379 1374 1375 + #define __vss_full(p, member, count, old) \ 1376 + (struct_size(p, member, count) + (old - struct_size(p, member, 0))) 1377 + 1380 1378 #define __vss(type, func, p, member, count) \ 1381 1379 struct type: func(p, member, count, type##_LEGACY_SIZEOF) 1382 1380 1383 1381 #define virtchnl_struct_size(p, m, c) \ 1384 1382 _Generic(*p, \ 1383 + __vss(virtchnl_vf_resource, __vss_full, p, m, c), \ 1384 + __vss(virtchnl_vsi_queue_config_info, __vss_full, p, m, c), \ 1385 + __vss(virtchnl_irq_map_info, __vss_full, p, m, c), \ 1386 + __vss(virtchnl_ether_addr_list, __vss_full, p, m, c), \ 1387 + __vss(virtchnl_vlan_filter_list, __vss_full, p, m, c), \ 1385 1388 __vss(virtchnl_rss_key, __vss_byone, p, m, c), \ 1386 1389 __vss(virtchnl_rss_lut, __vss_byone, p, m, c)) 1387 1390 ··· 1427 1414 valid_len = sizeof(struct virtchnl_rxq_info); 1428 1415 break; 1429 1416 case VIRTCHNL_OP_CONFIG_VSI_QUEUES: 1430 - valid_len = sizeof(struct virtchnl_vsi_queue_config_info); 1417 + valid_len = virtchnl_vsi_queue_config_info_LEGACY_SIZEOF; 1431 1418 if (msglen >= valid_len) { 1432 1419 struct virtchnl_vsi_queue_config_info *vqc = 1433 1420 (struct virtchnl_vsi_queue_config_info *)msg; 1434 - valid_len += (vqc->num_queue_pairs * 1435 - sizeof(struct 1436 - virtchnl_queue_pair_info)); 1421 + valid_len = virtchnl_struct_size(vqc, qpair, 1422 + vqc->num_queue_pairs); 1437 1423 if (vqc->num_queue_pairs == 0) 1438 1424 err_msg_format = true; 1439 1425 } 1440 1426 break; 1441 1427 case VIRTCHNL_OP_CONFIG_IRQ_MAP: 1442 - valid_len = sizeof(struct virtchnl_irq_map_info); 1428 + valid_len = virtchnl_irq_map_info_LEGACY_SIZEOF; 1443 1429 if (msglen >= valid_len) { 1444 1430 struct virtchnl_irq_map_info *vimi = 1445 1431 (struct virtchnl_irq_map_info *)msg; 1446 - valid_len += (vimi->num_vectors * 1447 - sizeof(struct virtchnl_vector_map)); 1432 + valid_len = virtchnl_struct_size(vimi, vecmap, 1433 + vimi->num_vectors); 1448 1434 if (vimi->num_vectors == 0) 1449 1435 err_msg_format = true; 1450 1436 } ··· 1454 1442 break; 1455 1443 case VIRTCHNL_OP_ADD_ETH_ADDR: 1456 1444 case VIRTCHNL_OP_DEL_ETH_ADDR: 1457 - valid_len = sizeof(struct virtchnl_ether_addr_list); 1445 + valid_len = virtchnl_ether_addr_list_LEGACY_SIZEOF; 1458 1446 if (msglen >= valid_len) { 1459 1447 struct virtchnl_ether_addr_list *veal = 1460 1448 (struct virtchnl_ether_addr_list *)msg; 1461 - valid_len += veal->num_elements * 1462 - sizeof(struct virtchnl_ether_addr); 1449 + valid_len = virtchnl_struct_size(veal, list, 1450 + veal->num_elements); 1463 1451 if (veal->num_elements == 0) 1464 1452 err_msg_format = true; 1465 1453 } 1466 1454 break; 1467 1455 case VIRTCHNL_OP_ADD_VLAN: 1468 1456 case VIRTCHNL_OP_DEL_VLAN: 1469 - valid_len = sizeof(struct virtchnl_vlan_filter_list); 1457 + valid_len = virtchnl_vlan_filter_list_LEGACY_SIZEOF; 1470 1458 if (msglen >= valid_len) { 1471 1459 struct virtchnl_vlan_filter_list *vfl = 1472 1460 (struct virtchnl_vlan_filter_list *)msg; 1473 - valid_len += vfl->num_elements * sizeof(u16); 1461 + valid_len = virtchnl_struct_size(vfl, vlan_id, 1462 + vfl->num_elements); 1474 1463 if (vfl->num_elements == 0) 1475 1464 err_msg_format = true; 1476 1465 }