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

add tests for libtdx_attest #240

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
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
12 changes: 12 additions & 0 deletions tests/checkbox/checkbox-provider-tdx/units/tests/jobs.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ command:
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH
setup-env-and-run test_guest_ita.py

id: tdx-guest/td-libtdx-attest
category_id: tdx-guest
flags: simple
_summary: Test guest libtdx_attest
depends:
after:
requires:
executable.name == 'qemu-system-x86_64'
command:
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH
setup-env-and-run test_guest_tdxattest.py

id: tdx-guest/td-guest-reboot
category_id: tdx-guest
flags: simple
Expand Down
30 changes: 28 additions & 2 deletions tests/lib/Qemu.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,21 @@ class QemuMachineType:
Qemu_Machine_Params = {
QemuEfiMachine.OVMF_Q35:['-machine', 'q35,kernel_irqchip=split'],
QemuEfiMachine.OVMF_Q35_TDX:[
'-object', 'tdx-guest,id=tdx',
'-machine', 'q35,kernel_irqchip=split,confidential-guest-support=tdx']
}
def __init__(self, machine = QemuEfiMachine.OVMF_Q35_TDX):
self.machine = machine
self.quote_sock = False
def enable_quote_socket(self):
self.quote_sock = True
def args(self):
return self.Qemu_Machine_Params[self.machine]
qemu_args = self.Qemu_Machine_Params[self.machine]
if self.machine == QemuEfiMachine.OVMF_Q35_TDX:
tdx_object = {'qom-type':'tdx-guest', 'id':'tdx'}
if self.quote_sock:
tdx_object.update({'quote-generation-socket':{'type': 'vsock', 'cid':'2','port':'4050'}})
qemu_args = ['-object', str(tdx_object)] + qemu_args
return qemu_args

class QemuBootType:
def __init__(self,
Expand Down Expand Up @@ -417,7 +425,25 @@ def rsync_file(self, fname, dest, sudo=False):
shell=True,
stdout=subprocess.DEVNULL)

def exec_command(self, cmd):
"""
Exec a command without checking the return code
Returns a triple:
- ret (return code)
- stdout
- stderr
"""
_, stdout, stderr = self.ssh_conn.exec_command(cmd)
ret_status = stdout.channel.recv_exit_status()
return ret_status, stdout, stderr

def check_exec(self, cmd, err_msg=None):
"""
Exec a command and check the return code
Returns a 2-tuple:
- stdout
- stderr
"""
_, stdout, stderr = self.ssh_conn.exec_command(cmd)
if err_msg==None:
err_msg=f'Execution of {cmd} failed'
Expand Down
7 changes: 3 additions & 4 deletions tests/tests/test_guest_ita.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,11 @@ def change_qgsd_state(state):


def run_trust_authority():
object = '{"qom-type":"tdx-guest","id":"tdx","quote-generation-socket":{"type": "vsock", "cid":"2","port":"4050"}}'
Qemu.QemuMachineType.Qemu_Machine_Params[Qemu.QemuEfiMachine.OVMF_Q35_TDX][1] = object

quote_str = ""
with Qemu.QemuMachine() as qm:
qm.qcmd.add_vsock(3)
spmcmillan marked this conversation as resolved.
Show resolved Hide resolved
machine = qm.qcmd.plugins['machine']
machine.enable_quote_socket()

qm.run()

ssh = Qemu.QemuSSH(qm)
Expand Down
123 changes: 123 additions & 0 deletions tests/tests/test_guest_tdxattest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
#
# Copyright 2024 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
#

import random
import string

import Qemu

# This file contains tests for the tdxattest lib in the guest
# The tdxattest library allows application to request a quote from the
# host system
# This request can be done through 2 channels:
# - vsock : the application connects directly to the QGSD service in the host
# - configfs tsm : the application use configsf tsm to ask the guest kernel
# to contact the QGSD service for the quote generation

def test_guest_tdxattest_tsm():
"""
TDX attest library
Success when only TSM is available
vsock support is disabled by removing the configuration file and not enabling
the vsock support in QEMU command line
"""
with Qemu.QemuMachine() as qm:
machine = qm.qcmd.plugins['machine']
machine.enable_quote_socket()

qm.run()
ssh = Qemu.QemuSSH(qm)

ssh.check_exec('rm -f /etc/tdx-attest.conf')
spmcmillan marked this conversation as resolved.
Show resolved Hide resolved
stdout, _ = ssh.check_exec('/usr/share/doc/libtdx-attest-dev/examples/test_tdx_attest')

assert 'Successfully get the TD Quote' in stdout.read().decode()

def test_guest_tdxattest_tsm_failure():
"""
TDX attest library
Failure if we force the lib to use TSM but QEMU does not have the
quote generation socket specified.
"""
with Qemu.QemuMachine() as qm:
qm.run()
ssh = Qemu.QemuSSH(qm)

ssh.check_exec('rm -f /etc/tdx-attest.conf')

ret, stdout, stderr = ssh.exec_command('/usr/share/doc/libtdx-attest-dev/examples/test_tdx_attest')
assert (ret != 0) and ('Failed to get the quote' in stderr.read().decode())

def test_guest_tdxattest_vsock():
"""
TDX attest library
Success when only vsock is available
ConfigFs TSM is disabled
"""
with Qemu.QemuMachine() as qm:
qm.qcmd.add_vsock(10)

qm.run()
ssh = Qemu.QemuSSH(qm)

disable_tsm(ssh)

stdout, _ = ssh.check_exec('/usr/share/doc/libtdx-attest-dev/examples/test_tdx_attest')

assert 'Successfully get the TD Quote' in stdout.read().decode()

def test_guest_tdxattest_vsock_failure():
"""
TDX attest library
Failure if we force the lib to use vsock and QEMU does not have the
vsock arguments specified
"""
with Qemu.QemuMachine() as qm:
qm.run()
ssh = Qemu.QemuSSH(qm)

disable_tsm(ssh)

ret, stdout, stderr = ssh.exec_command('/usr/share/doc/libtdx-attest-dev/examples/test_tdx_attest')
assert (ret != 0) and ('Failed to get the quote' in stderr.read().decode())

def test_guest_tdxattest_failure():
"""
TDX attest library
Fail when vsock and TSM are both disabled
"""
with Qemu.QemuMachine() as qm:
qm.run()
ssh = Qemu.QemuSSH(qm)

disable_tsm(ssh)
ssh.check_exec('rm -f /etc/tdx-attest.conf')

ret, stdout, stderr = ssh.exec_command('/usr/share/doc/libtdx-attest-dev/examples/test_tdx_attest')

assert (ret != 0) and ('Failed to get the quote' in stderr.read().decode())

def disable_tsm(ssh):
"""
Disable the configfs tsm
There is no official way to disable the configfs tsm functionality
but we can simulate configfs tsm errors by bind mounting an empty folder
on top of the tsm folder.
"""
tmp_folder_name=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(4))
ssh.check_exec(f'mkdir -p /tmp/{tmp_folder_name}')
ssh.check_exec(f'mount --bind /tmp/{tmp_folder_name} /sys/kernel/config/tsm/report/')