From 47b302d64624feb8aaa796693c5fc7486cb469ac Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Wed, 4 Jan 2017 23:03:45 -0800 Subject: [PATCH] net/qede/base: add handling of malicious VF Receive indication that VFs are malicious and pass it to the caller/clients and stop serving those VF's additional resource requests. Signed-off-by: Rasesh Mody --- drivers/net/qede/base/bcm_osal.h | 1 + drivers/net/qede/base/ecore_iov_api.h | 4 +- drivers/net/qede/base/ecore_l2.c | 26 +++++- drivers/net/qede/base/ecore_l2_api.h | 9 ++ drivers/net/qede/base/ecore_sriov.c | 125 ++++++++++++++++++++++---- drivers/net/qede/base/ecore_sriov.h | 1 + 6 files changed, 148 insertions(+), 18 deletions(-) diff --git a/drivers/net/qede/base/bcm_osal.h b/drivers/net/qede/base/bcm_osal.h index 0b446f2eb1..7682ea8440 100644 --- a/drivers/net/qede/base/bcm_osal.h +++ b/drivers/net/qede/base/bcm_osal.h @@ -323,6 +323,7 @@ u32 qede_find_first_zero_bit(unsigned long *, u32); #define OSAL_VF_SEND_MSG2PF(dev, done, msg, reply_addr, msg_size, reply_size) 0 #define OSAL_VF_CQE_COMPLETION(_dev_p, _cqe, _protocol) (0) #define OSAL_PF_VF_MSG(hwfn, vfid) 0 +#define OSAL_PF_VF_MALICIOUS(hwfn, vfid) nothing #define OSAL_IOV_CHK_UCAST(hwfn, vfid, params) 0 #define OSAL_IOV_POST_START_VPORT(hwfn, vf, vport_id, opaque_fid) nothing #define OSAL_IOV_VF_ACQUIRE(hwfn, vfid) 0 diff --git a/drivers/net/qede/base/ecore_iov_api.h b/drivers/net/qede/base/ecore_iov_api.h index bb8df82fbe..0b857bb918 100644 --- a/drivers/net/qede/base/ecore_iov_api.h +++ b/drivers/net/qede/base/ecore_iov_api.h @@ -52,6 +52,7 @@ enum ecore_iov_pf_to_vf_status { PFVF_STATUS_NOT_SUPPORTED, PFVF_STATUS_NO_RESOURCE, PFVF_STATUS_FORCED, + PFVF_STATUS_MALICIOUS, }; struct ecore_mcp_link_params; @@ -301,12 +302,13 @@ bool ecore_iov_is_vf_pending_flr(struct ecore_hwfn *p_hwfn, * @param p_hwfn * @param rel_vf_id - Relative VF ID * @param b_enabled_only - consider only enabled VF + * @param b_non_malicious - true iff we want to validate vf isn't malicious. * * @return bool - true for valid VF ID */ bool ecore_iov_is_valid_vfid(struct ecore_hwfn *p_hwfn, int rel_vf_id, - bool b_enabled_only); + bool b_enabled_only, bool b_non_malicious); /** * @brief Get VF's public info structure diff --git a/drivers/net/qede/base/ecore_l2.c b/drivers/net/qede/base/ecore_l2.c index a893cb90a1..9989ee48d6 100644 --- a/drivers/net/qede/base/ecore_l2.c +++ b/drivers/net/qede/base/ecore_l2.c @@ -36,9 +36,9 @@ ecore_sp_eth_vport_start(struct ecore_hwfn *p_hwfn, struct vport_start_ramrod_data *p_ramrod = OSAL_NULL; struct ecore_spq_entry *p_ent = OSAL_NULL; struct ecore_sp_init_data init_data; + u16 rx_mode = 0, tx_err = 0; u8 abs_vport_id = 0; enum _ecore_status_t rc = ECORE_NOTIMPL; - u16 rx_mode = 0; rc = ecore_fw_vport(p_hwfn, p_params->vport_id, &abs_vport_id); if (rc != ECORE_SUCCESS) @@ -71,6 +71,30 @@ ecore_sp_eth_vport_start(struct ecore_hwfn *p_hwfn, p_ramrod->rx_mode.state = OSAL_CPU_TO_LE16(rx_mode); + /* Handle requests for strict behavior on transmission errors */ + SET_FIELD(tx_err, ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE, + p_params->b_err_illegal_vlan_mode ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + SET_FIELD(tx_err, ETH_TX_ERR_VALS_PACKET_TOO_SMALL, + p_params->b_err_small_pkt ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + SET_FIELD(tx_err, ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR, + p_params->b_err_anti_spoof ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + SET_FIELD(tx_err, ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS, + p_params->b_err_illegal_inband_mode ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + SET_FIELD(tx_err, ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG, + p_params->b_err_vlan_insert_with_inband ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + SET_FIELD(tx_err, ETH_TX_ERR_VALS_MTU_VIOLATION, + p_params->b_err_big_pkt ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + SET_FIELD(tx_err, ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME, + p_params->b_err_ctrl_frame ? + ETH_TX_ERR_ASSERT_MALICIOUS : 0); + p_ramrod->tx_err_behav.values = OSAL_CPU_TO_LE16(tx_err); + /* TPA related fields */ OSAL_MEMSET(&p_ramrod->tpa_param, 0, sizeof(struct eth_vport_tpa_param)); diff --git a/drivers/net/qede/base/ecore_l2_api.h b/drivers/net/qede/base/ecore_l2_api.h index c338f5de7e..c12d97c9f4 100644 --- a/drivers/net/qede/base/ecore_l2_api.h +++ b/drivers/net/qede/base/ecore_l2_api.h @@ -274,6 +274,15 @@ struct ecore_sp_vport_start_params { bool zero_placement_offset; bool check_mac; bool check_ethtype; + + /* Strict behavior on transmission errors */ + bool b_err_illegal_vlan_mode; + bool b_err_illegal_inband_mode; + bool b_err_vlan_insert_with_inband; + bool b_err_small_pkt; + bool b_err_big_pkt; + bool b_err_anti_spoof; + bool b_err_ctrl_frame; }; /** diff --git a/drivers/net/qede/base/ecore_sriov.c b/drivers/net/qede/base/ecore_sriov.c index c2fbee872c..38c2db3dca 100644 --- a/drivers/net/qede/base/ecore_sriov.c +++ b/drivers/net/qede/base/ecore_sriov.c @@ -146,7 +146,7 @@ static enum _ecore_status_t ecore_sp_vf_stop(struct ecore_hwfn *p_hwfn, } bool ecore_iov_is_valid_vfid(struct ecore_hwfn *p_hwfn, int rel_vf_id, - bool b_enabled_only) + bool b_enabled_only, bool b_non_malicious) { if (!p_hwfn->pf_iov_info) { DP_NOTICE(p_hwfn->p_dev, true, "No iov info\n"); @@ -161,6 +161,10 @@ bool ecore_iov_is_valid_vfid(struct ecore_hwfn *p_hwfn, int rel_vf_id, b_enabled_only) return false; + if ((p_hwfn->pf_iov_info->vfs_array[rel_vf_id].b_malicious) && + b_non_malicious) + return false; + return true; } @@ -175,7 +179,8 @@ struct ecore_vf_info *ecore_iov_get_vf_info(struct ecore_hwfn *p_hwfn, return OSAL_NULL; } - if (ecore_iov_is_valid_vfid(p_hwfn, relative_vf_id, b_enabled_only)) + if (ecore_iov_is_valid_vfid(p_hwfn, relative_vf_id, + b_enabled_only, false)) vf = &p_hwfn->pf_iov_info->vfs_array[relative_vf_id]; else DP_ERR(p_hwfn, "ecore_iov_get_vf_info: VF[%d] is not enabled\n", @@ -612,7 +617,8 @@ enum _ecore_status_t ecore_iov_hw_info(struct ecore_hwfn *p_hwfn) return ECORE_SUCCESS; } -bool ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid) +bool _ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid, + bool b_fail_malicious) { /* Check PF supports sriov */ if (IS_VF(p_hwfn->p_dev) || !IS_ECORE_SRIOV(p_hwfn->p_dev) || @@ -620,12 +626,17 @@ bool ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid) return false; /* Check VF validity */ - if (!ecore_iov_is_valid_vfid(p_hwfn, vfid, true)) + if (!ecore_iov_is_valid_vfid(p_hwfn, vfid, true, b_fail_malicious)) return false; return true; } +bool ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid) +{ + return _ecore_iov_pf_sanity_check(p_hwfn, vfid, true); +} + void ecore_iov_set_vf_to_disable(struct ecore_dev *p_dev, u16 rel_vf_id, u8 to_disable) { @@ -746,6 +757,9 @@ ecore_iov_enable_vf_access(struct ecore_hwfn *p_hwfn, ecore_iov_vf_igu_reset(p_hwfn, p_ptt, vf); + /* It's possible VF was previously considered malicious */ + vf->b_malicious = false; + rc = ecore_mcp_config_vf_msix(p_hwfn, p_ptt, vf->abs_vf_id, vf->num_sbs); if (rc != ECORE_SUCCESS) @@ -3227,7 +3241,8 @@ void ecore_iov_process_mbx_req(struct ecore_hwfn *p_hwfn, p_vf, mbx->first_tlv.tl.type); /* check if tlv type is known */ - if (ecore_iov_tlv_supported(mbx->first_tlv.tl.type)) { + if (ecore_iov_tlv_supported(mbx->first_tlv.tl.type) && + !p_vf->b_malicious) { /* switch on the opcode */ switch (mbx->first_tlv.tl.type) { case CHANNEL_TLV_ACQUIRE: @@ -3270,6 +3285,27 @@ void ecore_iov_process_mbx_req(struct ecore_hwfn *p_hwfn, ecore_iov_vf_mbx_release(p_hwfn, p_ptt, p_vf); break; } + } else if (ecore_iov_tlv_supported(mbx->first_tlv.tl.type)) { + /* If we've received a message from a VF we consider malicious + * we ignore the messasge unless it's one for RELEASE, in which + * case we'll let it have the benefit of doubt, allowing the + * next loaded driver to start again. + */ + if (mbx->first_tlv.tl.type == CHANNEL_TLV_RELEASE) { + /* TODO - initiate FLR, remove malicious indication */ + DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, + "VF [%02x] - considered malicious, but wanted to RELEASE. TODO\n", + p_vf->abs_vf_id); + } else { + DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, + "VF [%02x] - considered malicious; Ignoring TLV [%04x]\n", + p_vf->abs_vf_id, mbx->first_tlv.tl.type); + } + + ecore_iov_prepare_resp(p_hwfn, p_ptt, p_vf, + mbx->first_tlv.tl.type, + sizeof(struct pfvf_def_resp_tlv), + PFVF_STATUS_MALICIOUS); } else { /* unknown TLV - this may belong to a VF driver from the future * - a version written after this PF driver was written, which @@ -3334,21 +3370,31 @@ void ecore_iov_pf_get_and_clear_pending_events(struct ecore_hwfn *p_hwfn, sizeof(u64) * ECORE_VF_ARRAY_LENGTH); } +static struct ecore_vf_info * +ecore_sriov_get_vf_from_absid(struct ecore_hwfn *p_hwfn, u16 abs_vfid) +{ + u8 min = (u8)p_hwfn->p_dev->p_iov_info->first_vf_in_pf; + + if (!_ecore_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min, false)) { + DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, + "Got indication for VF [abs 0x%08x] that cannot be" + " handled by PF\n", + abs_vfid); + return OSAL_NULL; + } + + return &p_hwfn->pf_iov_info->vfs_array[(u8)abs_vfid - min]; +} + static enum _ecore_status_t ecore_sriov_vfpf_msg(struct ecore_hwfn *p_hwfn, u16 abs_vfid, struct regpair *vf_msg) { - u8 min = (u8)p_hwfn->p_dev->p_iov_info->first_vf_in_pf; - struct ecore_vf_info *p_vf; + struct ecore_vf_info *p_vf = ecore_sriov_get_vf_from_absid(p_hwfn, + abs_vfid); - if (!ecore_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min)) { - DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, - "Got a message from VF [abs 0x%08x] that cannot be" - " handled by PF\n", - abs_vfid); + if (!p_vf) return ECORE_SUCCESS; - } - p_vf = &p_hwfn->pf_iov_info->vfs_array[(u8)abs_vfid - min]; /* List the physical address of the request so that handler * could later on copy the message from it. @@ -3358,6 +3404,25 @@ static enum _ecore_status_t ecore_sriov_vfpf_msg(struct ecore_hwfn *p_hwfn, return OSAL_PF_VF_MSG(p_hwfn, p_vf->relative_vf_id); } +static void ecore_sriov_vfpf_malicious(struct ecore_hwfn *p_hwfn, + struct malicious_vf_eqe_data *p_data) +{ + struct ecore_vf_info *p_vf; + + p_vf = ecore_sriov_get_vf_from_absid(p_hwfn, p_data->vfId); + + if (!p_vf) + return; + + DP_INFO(p_hwfn, + "VF [%d] - Malicious behavior [%02x]\n", + p_vf->abs_vf_id, p_data->errId); + + p_vf->b_malicious = true; + + OSAL_PF_VF_MALICIOUS(p_hwfn, p_vf->relative_vf_id); +} + enum _ecore_status_t ecore_sriov_eqe_event(struct ecore_hwfn *p_hwfn, u8 opcode, __le16 echo, @@ -3371,6 +3436,9 @@ enum _ecore_status_t ecore_sriov_eqe_event(struct ecore_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, "VF-FLR is still not supported\n"); return ECORE_SUCCESS; + case COMMON_EVENT_MALICIOUS_VF: + ecore_sriov_vfpf_malicious(p_hwfn, &data->malicious_vf); + return ECORE_SUCCESS; default: DP_INFO(p_hwfn->p_dev, "Unknown sriov eqe event 0x%02x\n", opcode); @@ -3393,7 +3461,7 @@ u16 ecore_iov_get_next_active_vf(struct ecore_hwfn *p_hwfn, u16 rel_vf_id) goto out; for (i = rel_vf_id; i < p_iov->total_vfs; i++) - if (ecore_iov_is_valid_vfid(p_hwfn, rel_vf_id, true)) + if (ecore_iov_is_valid_vfid(p_hwfn, rel_vf_id, true, false)) return i; out: @@ -3439,6 +3507,12 @@ void ecore_iov_bulletin_set_forced_mac(struct ecore_hwfn *p_hwfn, "Can not set forced MAC, invalid vfid [%d]\n", vfid); return; } + if (vf_info->b_malicious) { + DP_NOTICE(p_hwfn->p_dev, false, + "Can't set forced MAC to malicious VF [%d]\n", + vfid); + return; + } feature = 1 << MAC_ADDR_FORCED; OSAL_MEMCPY(vf_info->bulletin.p_virt->mac, mac, ETH_ALEN); @@ -3463,6 +3537,12 @@ enum _ecore_status_t ecore_iov_bulletin_set_mac(struct ecore_hwfn *p_hwfn, "Can not set MAC, invalid vfid [%d]\n", vfid); return ECORE_INVAL; } + if (vf_info->b_malicious) { + DP_NOTICE(p_hwfn->p_dev, false, + "Can't set MAC to malicious VF [%d]\n", + vfid); + return ECORE_INVAL; + } if (vf_info->bulletin.p_virt->valid_bitmap & (1 << MAC_ADDR_FORCED)) { DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, @@ -3488,7 +3568,14 @@ ecore_iov_bulletin_set_forced_untagged_default(struct ecore_hwfn *p_hwfn, vf_info = ecore_iov_get_vf_info(p_hwfn, (u16)vfid, true); if (!vf_info) { DP_NOTICE(p_hwfn->p_dev, true, - "Can not set forced MAC, invalid vfid [%d]\n", vfid); + "Can not set untagged default, invalid vfid [%d]\n", + vfid); + return ECORE_INVAL; + } + if (vf_info->b_malicious) { + DP_NOTICE(p_hwfn->p_dev, false, + "Can't set untagged default to malicious VF [%d]\n", + vfid); return ECORE_INVAL; } @@ -3553,6 +3640,12 @@ void ecore_iov_bulletin_set_forced_vlan(struct ecore_hwfn *p_hwfn, vfid); return; } + if (vf_info->b_malicious) { + DP_NOTICE(p_hwfn->p_dev, false, + "Can't set forced vlan to malicious VF [%d]\n", + vfid); + return; + } feature = 1 << VLAN_ADDR_FORCED; vf_info->bulletin.p_virt->pvid = pvid; diff --git a/drivers/net/qede/base/ecore_sriov.h b/drivers/net/qede/base/ecore_sriov.h index ed6ddc499e..3c5c68f9ee 100644 --- a/drivers/net/qede/base/ecore_sriov.h +++ b/drivers/net/qede/base/ecore_sriov.h @@ -97,6 +97,7 @@ struct ecore_vf_info { struct ecore_iov_vf_mbx vf_mbx; enum vf_state state; bool b_init; + bool b_malicious; u8 to_disable; struct ecore_bulletin bulletin;