Commit 0891c896 authored by Vignesh Sridhar's avatar Vignesh Sridhar Committed by Tony Nguyen

ice: warn about potentially malicious VFs

Attempt to detect malicious VFs and, if suspected, log the information but
keep going to allow the user to take any desired actions.

Potentially malicious VFs are identified by checking if the VFs are
transmitting too many messages via the PF-VF mailbox which could cause an
overflow of this channel resulting in denial of service. This is done by
creating a snapshot or static capture of the mailbox buffer which can be
traversed and in which the messages sent by VFs are tracked.
Co-developed-by: default avatarYashaswini Raghuram Prathivadi Bhayankaram <yashaswini.raghuram.prathivadi.bhayankaram@intel.com>
Signed-off-by: default avatarYashaswini Raghuram Prathivadi Bhayankaram <yashaswini.raghuram.prathivadi.bhayankaram@intel.com>
Co-developed-by: default avatarPaul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
Signed-off-by: default avatarPaul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
Co-developed-by: default avatarBrett Creeley <brett.creeley@intel.com>
Signed-off-by: default avatarBrett Creeley <brett.creeley@intel.com>
Signed-off-by: default avatarVignesh Sridhar <vignesh.sridhar@intel.com>
Tested-by: default avatarKonrad Jankowski <konrad0.jankowski@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 5d869070
......@@ -426,6 +426,7 @@ struct ice_pf {
u16 num_msix_per_vf;
/* used to ratelimit the MDD event logging */
unsigned long last_printed_mdd_jiffies;
DECLARE_BITMAP(malvfs, ICE_MAX_VF_COUNT);
DECLARE_BITMAP(state, ICE_STATE_NBITS);
DECLARE_BITMAP(flags, ICE_PF_FLAGS_NBITS);
unsigned long *avail_txqs; /* bitmap to track PF Tx queue usage */
......
......@@ -1193,6 +1193,10 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
case ICE_CTL_Q_MAILBOX:
cq = &hw->mailboxq;
qtype = "Mailbox";
/* we are going to try to detect a malicious VF, so set the
* state to begin detection
*/
hw->mbx_snapshot.mbx_buf.state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
break;
default:
dev_warn(dev, "Unknown control queue type 0x%x\n", q_type);
......@@ -1274,6 +1278,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
ice_vf_lan_overflow_event(pf, &event);
break;
case ice_mbx_opc_send_msg_to_pf:
if (!ice_is_malicious_vf(pf, &event, i, pending))
ice_vc_process_vf_msg(pf, &event);
break;
case ice_aqc_opc_fw_logging:
......
This diff is collapsed.
......@@ -4,7 +4,14 @@
#ifndef _ICE_SRIOV_H_
#define _ICE_SRIOV_H_
#include "ice_common.h"
#include "ice_type.h"
#include "ice_controlq.h"
/* Defining the mailbox message threshold as 63 asynchronous
* pending messages. Normal VF functionality does not require
* sending more than 63 asynchronous pending message.
*/
#define ICE_ASYNC_VF_MSG_THRESHOLD 63
#ifdef CONFIG_PCI_IOV
enum ice_status
......@@ -12,6 +19,17 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
u8 *msg, u16 msglen, struct ice_sq_cd *cd);
u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed);
enum ice_status
ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data,
u16 vf_id, bool *is_mal_vf);
enum ice_status
ice_mbx_clear_malvf(struct ice_mbx_snapshot *snap, unsigned long *all_malvfs,
u16 bitmap_len, u16 vf_id);
enum ice_status ice_mbx_init_snapshot(struct ice_hw *hw, u16 vf_count);
void ice_mbx_deinit_snapshot(struct ice_hw *hw);
enum ice_status
ice_mbx_report_malvf(struct ice_hw *hw, unsigned long *all_malvfs,
u16 bitmap_len, u16 vf_id, bool *report_malvf);
#else /* CONFIG_PCI_IOV */
static inline enum ice_status
ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw,
......
......@@ -630,6 +630,80 @@ struct ice_fw_log_cfg {
struct ice_fw_log_evnt evnts[ICE_AQC_FW_LOG_ID_MAX];
};
/* Enum defining the different states of the mailbox snapshot in the
* PF-VF mailbox overflow detection algorithm. The snapshot can be in
* states:
* 1. ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT - generate a new static snapshot
* within the mailbox buffer.
* 2. ICE_MAL_VF_DETECT_STATE_TRAVERSE - iterate through the mailbox snaphot
* 3. ICE_MAL_VF_DETECT_STATE_DETECT - track the messages sent per VF via the
* mailbox and mark any VFs sending more messages than the threshold limit set.
* 4. ICE_MAL_VF_DETECT_STATE_INVALID - Invalid mailbox state set to 0xFFFFFFFF.
*/
enum ice_mbx_snapshot_state {
ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT = 0,
ICE_MAL_VF_DETECT_STATE_TRAVERSE,
ICE_MAL_VF_DETECT_STATE_DETECT,
ICE_MAL_VF_DETECT_STATE_INVALID = 0xFFFFFFFF,
};
/* Structure to hold information of the static snapshot and the mailbox
* buffer data used to generate and track the snapshot.
* 1. state: the state of the mailbox snapshot in the malicious VF
* detection state handler ice_mbx_vf_state_handler()
* 2. head: head of the mailbox snapshot in a circular mailbox buffer
* 3. tail: tail of the mailbox snapshot in a circular mailbox buffer
* 4. num_iterations: number of messages traversed in circular mailbox buffer
* 5. num_msg_proc: number of messages processed in mailbox
* 6. num_pending_arq: number of pending asynchronous messages
* 7. max_num_msgs_mbx: maximum messages in mailbox for currently
* serviced work item or interrupt.
*/
struct ice_mbx_snap_buffer_data {
enum ice_mbx_snapshot_state state;
u32 head;
u32 tail;
u32 num_iterations;
u16 num_msg_proc;
u16 num_pending_arq;
u16 max_num_msgs_mbx;
};
/* Structure to track messages sent by VFs on mailbox:
* 1. vf_cntr: a counter array of VFs to track the number of
* asynchronous messages sent by each VF
* 2. vfcntr_len: number of entries in VF counter array
*/
struct ice_mbx_vf_counter {
u32 *vf_cntr;
u32 vfcntr_len;
};
/* Structure to hold data relevant to the captured static snapshot
* of the PF-VF mailbox.
*/
struct ice_mbx_snapshot {
struct ice_mbx_snap_buffer_data mbx_buf;
struct ice_mbx_vf_counter mbx_vf;
};
/* Structure to hold data to be used for capturing or updating a
* static snapshot.
* 1. num_msg_proc: number of messages processed in mailbox
* 2. num_pending_arq: number of pending asynchronous messages
* 3. max_num_msgs_mbx: maximum messages in mailbox for currently
* serviced work item or interrupt.
* 4. async_watermark_val: An upper threshold set by caller to determine
* if the pending arq count is large enough to assume that there is
* the possibility of a mailicious VF.
*/
struct ice_mbx_data {
u16 num_msg_proc;
u16 num_pending_arq;
u16 max_num_msgs_mbx;
u16 async_watermark_val;
};
/* Port hardware description */
struct ice_hw {
u8 __iomem *hw_addr;
......@@ -761,6 +835,7 @@ struct ice_hw {
DECLARE_BITMAP(fdir_perfect_fltr, ICE_FLTR_PTYPE_MAX);
struct mutex rss_locks; /* protect RSS configuration */
struct list_head rss_list_head;
struct ice_mbx_snapshot mbx_snapshot;
};
/* Statistics collected by each port, VSI, VEB, and S-channel */
......
......@@ -424,6 +424,14 @@ void ice_free_vfs(struct ice_pf *pf)
wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
}
}
/* clear malicious info if the VFs are getting released */
for (i = 0; i < tmp; i++)
if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs,
ICE_MAX_VF_COUNT, i))
dev_dbg(dev, "failed to clear malicious VF state for VF %u\n",
i);
clear_bit(ICE_VF_DIS, pf->state);
clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
}
......@@ -1257,6 +1265,11 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
if (!pf->num_alloc_vfs)
return false;
/* clear all malicious info if the VFs are getting reset */
ice_for_each_vf(pf, i)
if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs, ICE_MAX_VF_COUNT, i))
dev_dbg(dev, "failed to clear malicious VF state for VF %u\n", i);
/* If VFs have been disabled, there is no need to reset */
if (test_and_set_bit(ICE_VF_DIS, pf->state))
return false;
......@@ -1437,6 +1450,10 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
ice_vf_rebuild_vsi_with_release(vf);
ice_vf_post_vsi_rebuild(vf);
/* if the VF has been reset allow it to come up again */
if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs, ICE_MAX_VF_COUNT, vf->vf_id))
dev_dbg(dev, "failed to clear malicious VF state for VF %u\n", i);
return true;
}
......@@ -1769,6 +1786,7 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
struct ice_pf *pf = pci_get_drvdata(pdev);
struct device *dev = ice_pf_to_dev(pf);
enum ice_status status;
int err;
err = ice_check_sriov_allowed(pf);
......@@ -1777,6 +1795,7 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (!num_vfs) {
if (!pci_vfs_assigned(pdev)) {
ice_mbx_deinit_snapshot(&pf->hw);
ice_free_vfs(pf);
if (pf->lag)
ice_enable_lag(pf->lag);
......@@ -1787,9 +1806,15 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs)
return -EBUSY;
}
status = ice_mbx_init_snapshot(&pf->hw, num_vfs);
if (status)
return ice_status_to_errno(status);
err = ice_pci_sriov_ena(pf, num_vfs);
if (err)
if (err) {
ice_mbx_deinit_snapshot(&pf->hw);
return err;
}
if (pf->lag)
ice_disable_lag(pf->lag);
......@@ -4255,3 +4280,70 @@ void ice_restore_all_vfs_msi_state(struct pci_dev *pdev)
}
}
}
/**
* ice_is_malicious_vf - helper function to detect a malicious VF
* @pf: ptr to struct ice_pf
* @event: pointer to the AQ event
* @num_msg_proc: the number of messages processed so far
* @num_msg_pending: the number of messages peinding in admin queue
*/
bool
ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event,
u16 num_msg_proc, u16 num_msg_pending)
{
s16 vf_id = le16_to_cpu(event->desc.retval);
struct device *dev = ice_pf_to_dev(pf);
struct ice_mbx_data mbxdata;
enum ice_status status;
bool malvf = false;
struct ice_vf *vf;
if (ice_validate_vf_id(pf, vf_id))
return false;
vf = &pf->vf[vf_id];
/* Check if VF is disabled. */
if (test_bit(ICE_VF_STATE_DIS, vf->vf_states))
return false;
mbxdata.num_msg_proc = num_msg_proc;
mbxdata.num_pending_arq = num_msg_pending;
mbxdata.max_num_msgs_mbx = pf->hw.mailboxq.num_rq_entries;
#define ICE_MBX_OVERFLOW_WATERMARK 64
mbxdata.async_watermark_val = ICE_MBX_OVERFLOW_WATERMARK;
/* check to see if we have a malicious VF */
status = ice_mbx_vf_state_handler(&pf->hw, &mbxdata, vf_id, &malvf);
if (status)
return false;
if (malvf) {
bool report_vf = false;
/* if the VF is malicious and we haven't let the user
* know about it, then let them know now
*/
status = ice_mbx_report_malvf(&pf->hw, pf->malvfs,
ICE_MAX_VF_COUNT, vf_id,
&report_vf);
if (status)
dev_dbg(dev, "Error reporting malicious VF\n");
if (report_vf) {
struct ice_vsi *pf_vsi = ice_get_main_vsi(pf);
if (pf_vsi)
dev_warn(dev, "VF MAC %pM on PF MAC %pM is generating asynchronous messages and may be overflowing the PF message queue. Please see the Adapter User Guide for more information\n",
&vf->dflt_lan_addr.addr[0],
pf_vsi->netdev->dev_addr);
}
return true;
}
/* if there was an error in detection or the VF is not malicious then
* return false
*/
return false;
}
......@@ -119,6 +119,9 @@ void ice_vc_notify_reset(struct ice_pf *pf);
bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr);
bool ice_reset_vf(struct ice_vf *vf, bool is_vflr);
void ice_restore_all_vfs_msi_state(struct pci_dev *pdev);
bool
ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event,
u16 num_msg_proc, u16 num_msg_pending);
int
ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos,
......@@ -158,6 +161,15 @@ bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id);
#define ice_print_vf_rx_mdd_event(vf) do {} while (0)
#define ice_restore_all_vfs_msi_state(pdev) do {} while (0)
static inline bool
ice_is_malicious_vf(struct ice_pf __always_unused *pf,
struct ice_rq_event_info __always_unused *event,
u16 __always_unused num_msg_proc,
u16 __always_unused num_msg_pending)
{
return false;
}
static inline bool
ice_reset_all_vfs(struct ice_pf __always_unused *pf,
bool __always_unused is_vflr)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment