Skip to content

Commit 91fc617

Browse files
committed
Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue
Tony Nguyen says: ==================== i40e: virtchnl improvements Przemek Kitszel says: Improvements hardening PF-VF communication for i40e driver. This patchset targets several issues that can cause undefined behavior or be exploited in some other way. * '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue: i40e: improve VF MAC filters accounting i40e: add mask to apply valid bits for itr_idx i40e: add max boundary check for VF filters i40e: fix validation of VF state in get resources i40e: fix input validation logic for action_meta i40e: fix idx validation in config queues msg i40e: fix idx validation in i40e_validate_queue_map i40e: add validation for ring_len param ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 3491bb7 + b99dd77 commit 91fc617

File tree

4 files changed

+90
-52
lines changed

4 files changed

+90
-52
lines changed

drivers/net/ethernet/intel/i40e/i40e.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,8 @@ struct i40e_mac_filter *i40e_add_mac_filter(struct i40e_vsi *vsi,
12781278
const u8 *macaddr);
12791279
int i40e_del_mac_filter(struct i40e_vsi *vsi, const u8 *macaddr);
12801280
bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi);
1281-
int i40e_count_filters(struct i40e_vsi *vsi);
1281+
int i40e_count_all_filters(struct i40e_vsi *vsi);
1282+
int i40e_count_active_filters(struct i40e_vsi *vsi);
12821283
struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr);
12831284
void i40e_vlan_stripping_enable(struct i40e_vsi *vsi);
12841285
static inline bool i40e_is_sw_dcb(struct i40e_pf *pf)

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,12 +1243,30 @@ void i40e_update_stats(struct i40e_vsi *vsi)
12431243
}
12441244

12451245
/**
1246-
* i40e_count_filters - counts VSI mac filters
1246+
* i40e_count_all_filters - counts VSI MAC filters
12471247
* @vsi: the VSI to be searched
12481248
*
1249-
* Returns count of mac filters
1250-
**/
1251-
int i40e_count_filters(struct i40e_vsi *vsi)
1249+
* Return: count of MAC filters in any state.
1250+
*/
1251+
int i40e_count_all_filters(struct i40e_vsi *vsi)
1252+
{
1253+
struct i40e_mac_filter *f;
1254+
struct hlist_node *h;
1255+
int bkt, cnt = 0;
1256+
1257+
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
1258+
cnt++;
1259+
1260+
return cnt;
1261+
}
1262+
1263+
/**
1264+
* i40e_count_active_filters - counts VSI MAC filters
1265+
* @vsi: the VSI to be searched
1266+
*
1267+
* Return: count of active MAC filters.
1268+
*/
1269+
int i40e_count_active_filters(struct i40e_vsi *vsi)
12521270
{
12531271
struct i40e_mac_filter *f;
12541272
struct hlist_node *h;

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

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,
448448
(qtype << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
449449
(pf_queue_id << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
450450
BIT(I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) |
451-
(itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT);
451+
FIELD_PREP(I40E_QINT_RQCTL_ITR_INDX_MASK, itr_idx);
452452
wr32(hw, reg_idx, reg);
453453
}
454454

@@ -653,6 +653,13 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id,
653653

654654
/* only set the required fields */
655655
tx_ctx.base = info->dma_ring_addr / 128;
656+
657+
/* ring_len has to be multiple of 8 */
658+
if (!IS_ALIGNED(info->ring_len, 8) ||
659+
info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) {
660+
ret = -EINVAL;
661+
goto error_context;
662+
}
656663
tx_ctx.qlen = info->ring_len;
657664
tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[0]);
658665
tx_ctx.rdylist_act = 0;
@@ -716,6 +723,13 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,
716723

717724
/* only set the required fields */
718725
rx_ctx.base = info->dma_ring_addr / 128;
726+
727+
/* ring_len has to be multiple of 32 */
728+
if (!IS_ALIGNED(info->ring_len, 32) ||
729+
info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) {
730+
ret = -EINVAL;
731+
goto error_param;
732+
}
719733
rx_ctx.qlen = info->ring_len;
720734

721735
if (info->splithdr_enabled) {
@@ -1450,6 +1464,7 @@ static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
14501464
* functions that may still be running at this point.
14511465
*/
14521466
clear_bit(I40E_VF_STATE_INIT, &vf->vf_states);
1467+
clear_bit(I40E_VF_STATE_RESOURCES_LOADED, &vf->vf_states);
14531468

14541469
/* In the case of a VFLR, the HW has already reset the VF and we
14551470
* just need to clean up, so don't hit the VFRTRIG register.
@@ -2116,7 +2131,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
21162131
size_t len = 0;
21172132
int ret;
21182133

2119-
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_INIT)) {
2134+
i40e_sync_vf_state(vf, I40E_VF_STATE_INIT);
2135+
2136+
if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states) ||
2137+
test_bit(I40E_VF_STATE_RESOURCES_LOADED, &vf->vf_states)) {
21202138
aq_ret = -EINVAL;
21212139
goto err;
21222140
}
@@ -2219,6 +2237,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
22192237
vf->default_lan_addr.addr);
22202238
}
22212239
set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
2240+
set_bit(I40E_VF_STATE_RESOURCES_LOADED, &vf->vf_states);
22222241

22232242
err:
22242243
/* send the response back to the VF */
@@ -2381,7 +2400,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
23812400
}
23822401

23832402
if (vf->adq_enabled) {
2384-
if (idx >= ARRAY_SIZE(vf->ch)) {
2403+
if (idx >= vf->num_tc) {
23852404
aq_ret = -ENODEV;
23862405
goto error_param;
23872406
}
@@ -2402,7 +2421,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
24022421
* to its appropriate VSIs based on TC mapping
24032422
*/
24042423
if (vf->adq_enabled) {
2405-
if (idx >= ARRAY_SIZE(vf->ch)) {
2424+
if (idx >= vf->num_tc) {
24062425
aq_ret = -ENODEV;
24072426
goto error_param;
24082427
}
@@ -2452,8 +2471,10 @@ static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id,
24522471
u16 vsi_queue_id, queue_id;
24532472

24542473
for_each_set_bit(vsi_queue_id, &queuemap, I40E_MAX_VSI_QP) {
2455-
if (vf->adq_enabled) {
2456-
vsi_id = vf->ch[vsi_queue_id / I40E_MAX_VF_VSI].vsi_id;
2474+
u16 idx = vsi_queue_id / I40E_MAX_VF_VSI;
2475+
2476+
if (vf->adq_enabled && idx < vf->num_tc) {
2477+
vsi_id = vf->ch[idx].vsi_id;
24572478
queue_id = (vsi_queue_id % I40E_DEFAULT_QUEUES_PER_VF);
24582479
} else {
24592480
queue_id = vsi_queue_id;
@@ -2841,24 +2862,6 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg)
28412862
(u8 *)&stats, sizeof(stats));
28422863
}
28432864

2844-
/**
2845-
* i40e_can_vf_change_mac
2846-
* @vf: pointer to the VF info
2847-
*
2848-
* Return true if the VF is allowed to change its MAC filters, false otherwise
2849-
*/
2850-
static bool i40e_can_vf_change_mac(struct i40e_vf *vf)
2851-
{
2852-
/* If the VF MAC address has been set administratively (via the
2853-
* ndo_set_vf_mac command), then deny permission to the VF to
2854-
* add/delete unicast MAC addresses, unless the VF is trusted
2855-
*/
2856-
if (vf->pf_set_mac && !vf->trusted)
2857-
return false;
2858-
2859-
return true;
2860-
}
2861-
28622865
#define I40E_MAX_MACVLAN_PER_HW 3072
28632866
#define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW / \
28642867
(num_ports))
@@ -2897,8 +2900,10 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
28972900
struct i40e_pf *pf = vf->pf;
28982901
struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx];
28992902
struct i40e_hw *hw = &pf->hw;
2900-
int mac2add_cnt = 0;
2901-
int i;
2903+
int i, mac_add_max, mac_add_cnt = 0;
2904+
bool vf_trusted;
2905+
2906+
vf_trusted = test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
29022907

29032908
for (i = 0; i < al->num_elements; i++) {
29042909
struct i40e_mac_filter *f;
@@ -2918,9 +2923,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
29182923
* The VF may request to set the MAC address filter already
29192924
* assigned to it so do not return an error in that case.
29202925
*/
2921-
if (!i40e_can_vf_change_mac(vf) &&
2922-
!is_multicast_ether_addr(addr) &&
2923-
!ether_addr_equal(addr, vf->default_lan_addr.addr)) {
2926+
if (!vf_trusted && !is_multicast_ether_addr(addr) &&
2927+
vf->pf_set_mac && !ether_addr_equal(addr, vf->default_lan_addr.addr)) {
29242928
dev_err(&pf->pdev->dev,
29252929
"VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
29262930
return -EPERM;
@@ -2929,29 +2933,33 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
29292933
/*count filters that really will be added*/
29302934
f = i40e_find_mac(vsi, addr);
29312935
if (!f)
2932-
++mac2add_cnt;
2936+
++mac_add_cnt;
29332937
}
29342938

29352939
/* If this VF is not privileged, then we can't add more than a limited
2936-
* number of addresses. Check to make sure that the additions do not
2937-
* push us over the limit.
2938-
*/
2939-
if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
2940-
if ((i40e_count_filters(vsi) + mac2add_cnt) >
2941-
I40E_VC_MAX_MAC_ADDR_PER_VF) {
2942-
dev_err(&pf->pdev->dev,
2943-
"Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n");
2944-
return -EPERM;
2945-
}
2946-
/* If this VF is trusted, it can use more resources than untrusted.
2940+
* number of addresses.
2941+
*
2942+
* If this VF is trusted, it can use more resources than untrusted.
29472943
* However to ensure that every trusted VF has appropriate number of
29482944
* resources, divide whole pool of resources per port and then across
29492945
* all VFs.
29502946
*/
2951-
} else {
2952-
if ((i40e_count_filters(vsi) + mac2add_cnt) >
2953-
I40E_VC_MAX_MACVLAN_PER_TRUSTED_VF(pf->num_alloc_vfs,
2954-
hw->num_ports)) {
2947+
if (!vf_trusted)
2948+
mac_add_max = I40E_VC_MAX_MAC_ADDR_PER_VF;
2949+
else
2950+
mac_add_max = I40E_VC_MAX_MACVLAN_PER_TRUSTED_VF(pf->num_alloc_vfs, hw->num_ports);
2951+
2952+
/* VF can replace all its filters in one step, in this case mac_add_max
2953+
* will be added as active and another mac_add_max will be in
2954+
* a to-be-removed state. Account for that.
2955+
*/
2956+
if ((i40e_count_active_filters(vsi) + mac_add_cnt) > mac_add_max ||
2957+
(i40e_count_all_filters(vsi) + mac_add_cnt) > 2 * mac_add_max) {
2958+
if (!vf_trusted) {
2959+
dev_err(&pf->pdev->dev,
2960+
"Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n");
2961+
return -EPERM;
2962+
} else {
29552963
dev_err(&pf->pdev->dev,
29562964
"Cannot add more MAC addresses, trusted VF exhausted it's resources\n");
29572965
return -EPERM;
@@ -3587,7 +3595,7 @@ static int i40e_validate_cloud_filter(struct i40e_vf *vf,
35873595

35883596
/* action_meta is TC number here to which the filter is applied */
35893597
if (!tc_filter->action_meta ||
3590-
tc_filter->action_meta > vf->num_tc) {
3598+
tc_filter->action_meta >= vf->num_tc) {
35913599
dev_info(&pf->pdev->dev, "VF %d: Invalid TC number %u\n",
35923600
vf->vf_id, tc_filter->action_meta);
35933601
goto err;
@@ -3884,6 +3892,8 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
38843892
aq_ret);
38853893
}
38863894

3895+
#define I40E_MAX_VF_CLOUD_FILTER 0xFF00
3896+
38873897
/**
38883898
* i40e_vc_add_cloud_filter
38893899
* @vf: pointer to the VF info
@@ -3923,6 +3933,14 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
39233933
goto err_out;
39243934
}
39253935

3936+
if (vf->num_cloud_filters >= I40E_MAX_VF_CLOUD_FILTER) {
3937+
dev_warn(&pf->pdev->dev,
3938+
"VF %d: Max number of filters reached, can't apply cloud filter\n",
3939+
vf->vf_id);
3940+
aq_ret = -ENOSPC;
3941+
goto err_out;
3942+
}
3943+
39263944
cfilter = kzalloc(sizeof(*cfilter), GFP_KERNEL);
39273945
if (!cfilter) {
39283946
aq_ret = -ENOMEM;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ enum i40e_vf_states {
4141
I40E_VF_STATE_MC_PROMISC,
4242
I40E_VF_STATE_UC_PROMISC,
4343
I40E_VF_STATE_PRE_ENABLE,
44-
I40E_VF_STATE_RESETTING
44+
I40E_VF_STATE_RESETTING,
45+
I40E_VF_STATE_RESOURCES_LOADED,
4546
};
4647

4748
/* VF capabilities */

0 commit comments

Comments
 (0)