Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vmsdk: add vsock support on TDX quote fetching #4

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 66 additions & 7 deletions src/python/cctrusted_vm/cvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
import logging
import struct
import fcntl
import socket
from abc import abstractmethod
from cctrusted_base.api import CCTrustedApi
from cctrusted_base.imr import TcgIMR
from cctrusted_base.ccreport import CcReport
from cctrusted_base.tcg import TcgAlgorithmRegistry
from cctrusted_base.tdx.common import TDX_VERSION_1_0, TDX_VERSION_1_5
from cctrusted_base.tdx.rtmr import TdxRTMR
from cctrusted_base.tdx.quote import TdxQuoteReq10, TdxQuoteReq15
from cctrusted_base.tdx.quote import TdxQuoteReq10, TdxQuoteReq15, TdxQuote
from cctrusted_base.tdx.report import TdxReportReq10, TdxReportReq15

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -216,6 +217,7 @@ class TdxVM(ConfidentialVM):
ACPI_TABLE_FILE = "/sys/firmware/acpi/tables/CCEL"
ACPI_TABLE_DATA_FILE = "/sys/firmware/acpi/tables/data/CCEL"
IMA_DATA_FILE = "/sys/kernel/security/integrity/ima/ascii_runtime_measurements"
CFG_FILE_PATH = "/etc/tdx-attest.conf"

def __init__(self):
ConfidentialVM.__init__(self, CCTrustedApi.TYPE_CC_TDX)
Expand Down Expand Up @@ -391,6 +393,69 @@ def get_cc_report(self, nonce: bytearray, data: bytearray, extraArgs) -> CcRepor
self.process_cc_report(input_data)
report_bytes = self.tdreport.data

if self.version is TDX_VERSION_1_0:
quote_req = TdxQuoteReq10()
elif self.version is TDX_VERSION_1_5:
quote_req = TdxQuoteReq15()

# Use tdvmcall to get TD Quote by default
tdvmcall_flag = True

# Check if vsock port specified in TDX attest config
# If specified, use vsock to get quote
if os.path.exists(TdxVM.CFG_FILE_PATH):
LOG.info("Found TDX Config file at %s", TdxVM.CFG_FILE_PATH)
try:
with open(TdxVM.CFG_FILE_PATH, 'rb') as cfg_file:
cfg_info = [line.rstrip() for line in cfg_file]
for line in cfg_info:
line = line.decode("utf-8").replace(" ", "")
if "port=" in line:
LOG.info("Vsock port number specified. Use vsock for quote fetching.")
tdvmcall_flag = False
port = int(line.partition("port=")[2])
if port <= 0 or port > 65535:
LOG.error(
"Invalid vsock port number specified. Fallback to tdvmcall.")
tdvmcall_flag = True
break
except(PermissionError, OSError):
LOG.error("Need root permission to open file %s", TdxVM.CFG_FILE_PATH)

if not tdvmcall_flag:
# Setup socket to connect qgs socket on host
with socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM, 0) as sock:
Ruoyu-y marked this conversation as resolved.
Show resolved Hide resolved
sock.settimeout(30)
sock.connect((socket.VMADDR_CID_HOST, port))

header_size = 4
# Generate p_blob_payload buffer
qgs_msg = quote_req.qgs_msg_quote_req(report_bytes)
msg_size = len(qgs_msg)

p_blob_payload = bytearray(msg_size.to_bytes(header_size, "big"))
p_blob_payload[header_size:] = qgs_msg[:msg_size]

# Send quote request
nsent = sock.send(p_blob_payload)
Ruoyu-y marked this conversation as resolved.
Show resolved Hide resolved
LOG.debug("Sent %d bytes for Quote request.", nsent)

# Receive quote
header = sock.recv(header_size)
in_msg_size = 0
for i in range(header_size):
in_msg_size = (in_msg_size << 8) + (header[i] & 0xFF)
qgs_resp = sock.recv(in_msg_size)
LOG.debug("Received %d bytes as Quote response", in_msg_size)

sock.close()
tdquote = quote_req.qgs_msg_quote_resp(qgs_resp)
return TdxQuote(tdquote)

# Fetch quote through tdvmcall
# pylint: disable=E1111
req_buf = quote_req.prepare_reqbuf(report_bytes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it miss an "else" here corresponding to line 414? Otherwise it will execute line 452 fetching quote through tdvmcall anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the end of the 'if' condition, it just returns the tdquote as output. Will skip the tdvmcall part.


# Open TDX guest device node
dev_path = self.DEVICE_NODE_PATH[self.version]
try:
Expand All @@ -401,12 +466,6 @@ def get_cc_report(self, nonce: bytearray, data: bytearray, extraArgs) -> CcRepor
LOG.debug("Successful open device node %s", dev_path)

# Run ioctl command to get TD Quote
if self.version is TDX_VERSION_1_0:
quote_req = TdxQuoteReq10()
elif self.version is TDX_VERSION_1_5:
quote_req = TdxQuoteReq15()
# pylint: disable=E1111
req_buf = quote_req.prepare_reqbuf(report_bytes)
try:
fcntl.ioctl(tdx_dev, self.IOCTL_GET_QUOTE[self.version], req_buf)
except OSError as e:
Expand Down
Loading