pyVmomi script to confirm Speculative Store Bypass Disable (SSBD) mitigation on vSphere patches

Few hours back, VMware released vSphere patches to mitigate “Speculative Store Bypass Disable (SSBD)” security issue. Please take a look at this KB for more details. In this post, as I did in the past, I am going to provide you a pyVmomi script to confirm whether vCenter server, ESXi hypervisor and microcode patches are applied or not to mitigate this critical security issue. Before we look into script, one of the important points you should note that, these latest vSphere (both vCenter server and ESXi) patches  are cumulative &  if you haven’t applied earlier spectre vulnerability patches [released as on 20th March] yet, you can directly apply these patches to get earlier fixes as well.

pyVmomi script to confirm SSBD mitigation

Notes:

  • This script works for all vSphere releases i.e. 5.5, 6.0, 6.5, 6.7.
  • This script i.e. confirm_ssbd_patch.py is available on my github repo as well.
  • Since this patch is cumulative, focus in this script is only SSBD cpubit
  • This script takes VCIP, username, password and cluster-name (with or without EVC) as parameter.
  • Please take a note of line #72 on SSL/TLS protocol
  • As specified in the KB, you need to perform VM power-cycle post patch application.

[python]
# Author: Vikas Shitole
# Product: vCenter server
# Description: Script to confirm whether vCenter server, hypervisor and microcode patches are applied or not : vCenter/ESXi patches for Speculative Store Bypass Disable vulnerability.
# Reference: https://kb.vmware.com/s/article/55111
# How to setup pyVmomi environment?:
# Linux: https://vthinkbeyondvm.com/how-did-i-get-started-with-the-vsphere-python-sdk-pyvmomi-on-ubuntu-distro/
#Windows: https://vthinkbeyondvm.com/getting-started-with-pyvmomi-on-windows-supports-vsphere-6-7/

from pyVim.connect import SmartConnect, Disconnect
from pyVmomi import vim
import atexit
import ssl
import sys
import argparse
import getpass

# Script to confirm whether EVC cluster is patched or not for Spectre vulenerability.

def get_args():
""" Get arguments from CLI """
parser = argparse.ArgumentParser(
description=’Arguments for talking to vCenter’)

parser.add_argument(‘-s’, ‘–host’,
required=True,
action=’store’,
help=’vSpehre service to connect to’)

parser.add_argument(‘-o’, ‘–port’,
type=int,
default=443,
action=’store’,
help=’Port to connect on’)

parser.add_argument(‘-u’, ‘–user’,
required=True,
action=’store’,
help=’Username to use’)

parser.add_argument(‘-p’, ‘–password’,
required=False,
action=’store’,
help=’Password to use’)

parser.add_argument(‘-c’, ‘–cluster’,
required=True,
action=’store’,
default=None,
help=’Name of the cluster you wish to check’)

args = parser.parse_args()

if not args.password:
args.password = getpass.getpass(
prompt=’Enter vCenter password:’)

return args

# Below method helps us to get MOR of the object (vim type) that we passed.
def get_obj(content, vimtype, name):
obj = None
container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)
for c in container.view:
if name and c.name == name:
obj = c
break
container.Destroy()
return obj

args = get_args()
s=ssl.SSLContext(ssl.PROTOCOL_SSLv23) # For VC 6.5/6.0 s=ssl.SSLContext(ssl.PROTOCOL_TLSv1)
s.verify_mode=ssl.CERT_NONE
si= SmartConnect(host=args.host, user=args.user, pwd=args.password,sslContext=s)
content=si.content
cluster_name=args.cluster

print ("————————————-")
#Check whether vCenter server is patched or not
supported_evc_mode=si.capability.supportedEVCMode
# It is not required to check "ivy-bridge" EVC mode, you can choose any EVC mode from "intel-penryn" onwords.
for evc_mode in supported_evc_mode:
if(evc_mode.key == "intel-ivybridge"):
ivy_masks=evc_mode.featureMask
break

vCenter_patched=False
for capability in ivy_masks:
if(capability.key in ["cpuid.SSBD"] and capability.value=="Val:1"):
print ("Found::"+capability.key)
vCenter_patched=True
if(not vCenter_patched):
print ("No new cpubit found, hence vCenter server is NOT patched")
else:
print ("New CPU bit is found, hence vCenter Server is patched")
print ("Current vCenter server build::"+si.content.about.fullName)

#Cluster object
cluster = get_obj(content,[vim.ClusterComputeResource],cluster_name)
if(not cluster):
print ("Cluster not found, please enter correct EVC cluster name")
quit()

print ("Cluster Name:"+cluster.name)

# Get all the hosts available inside cluster
hosts = cluster.host

#Iterate through each host to get MaxEVC mode supported on the host
for host in hosts:
print ("———————————-")
print ("Host:"+host.name)
feature_capabilities = host.config.featureCapability
flag=False
for capability in feature_capabilities:
if(capability.key in ["cpuid.SSBD"] and capability.value=="1"):
print ("Found::"+capability.key)
flag=True
if(not flag):
print ("No new cpubit found, hence "+host.name+" is NOT patched")
else:
print ("New CPU bit is found, hence "+host.name+" is patched")

atexit.register(Disconnect, si)

[/python]

Let us take a look at below output.

Output

C:\Professional\vThinkBeyondVM\Spectre posts>python hosts_patched_ssbd.py -s 10.20.30.35 -u [email protected] -c “New Cluster”
Enter vCenter password:
————————————-
Found::cpuid.SSBD
New CPU bit is found, hence vCenter Server is patched
Current vCenter server build::VMware vCenter Server 6.7.0 build-8833179
Cluster Name:New Cluster
———————————-
Host: 10.20.30.51
No new cpubit found, hence 10.20.30.51 is NOT patched
———————————-
Host: 10.20.30.52
Found::cpuid.SSBD
New CPU bit is found, hence 10.20.30.51 is patched

Above output shows that vCenter server is patched and one of the two ESXi hosts is patched successfully.

Further learning resources
  1. per-VM EVC tutorial
  2.  Part-1: Managing Cluster level EVC using pyVmomi
  3. Part 2: Managing Cluster level EVC using pyVmomi
  4. Tutorial on getting started pyVmomi  on linux
  5. Tutorial on getting started pyVmomi on Windows

I hope you will find this post useful, please stay tuned for my next blog post on per-VM EVC wrt to these mitigation patches.