| #!/usr/bin/env python3 |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| from struct import pack |
| from time import sleep |
| |
| import errno |
| import glob |
| import os |
| import subprocess |
| |
| try: |
| import pytest |
| except ImportError: |
| print("Unable to import pytest python module.") |
| print("\nIf not already installed, you may do so with:") |
| print("\t\tpip3 install pytest") |
| exit(1) |
| |
| SOCKETS = glob.glob('/sys/bus/auxiliary/devices/intel_vsec.sdsi.*') |
| NUM_SOCKETS = len(SOCKETS) |
| |
| MODULE_NAME = 'intel_sdsi' |
| DEV_PREFIX = 'intel_vsec.sdsi' |
| CLASS_DIR = '/sys/bus/auxiliary/devices' |
| GUID = "0x6dd191" |
| |
| def read_bin_file(file): |
| with open(file, mode='rb') as f: |
| content = f.read() |
| return content |
| |
| def get_dev_file_path(socket, file): |
| return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' + file |
| |
| def kmemleak_enabled(): |
| kmemleak = "/sys/kernel/debug/kmemleak" |
| return os.path.isfile(kmemleak) |
| |
| class TestSDSiDriver: |
| def test_driver_loaded(self): |
| lsmod_p = subprocess.Popen(('lsmod'), stdout=subprocess.PIPE) |
| result = subprocess.check_output(('grep', '-q', MODULE_NAME), stdin=lsmod_p.stdout) |
| |
| @pytest.mark.parametrize('socket', range(0, NUM_SOCKETS)) |
| class TestSDSiFilesClass: |
| |
| def read_value(self, file): |
| f = open(file, "r") |
| value = f.read().strip("\n") |
| return value |
| |
| def get_dev_folder(self, socket): |
| return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' |
| |
| def test_sysfs_files_exist(self, socket): |
| folder = self.get_dev_folder(socket) |
| print (folder) |
| assert os.path.isfile(folder + "guid") == True |
| assert os.path.isfile(folder + "provision_akc") == True |
| assert os.path.isfile(folder + "provision_cap") == True |
| assert os.path.isfile(folder + "state_certificate") == True |
| assert os.path.isfile(folder + "registers") == True |
| |
| def test_sysfs_file_permissions(self, socket): |
| folder = self.get_dev_folder(socket) |
| mode = os.stat(folder + "guid").st_mode & 0o777 |
| assert mode == 0o444 # Read all |
| mode = os.stat(folder + "registers").st_mode & 0o777 |
| assert mode == 0o400 # Read owner |
| mode = os.stat(folder + "provision_akc").st_mode & 0o777 |
| assert mode == 0o200 # Read owner |
| mode = os.stat(folder + "provision_cap").st_mode & 0o777 |
| assert mode == 0o200 # Read owner |
| mode = os.stat(folder + "state_certificate").st_mode & 0o777 |
| assert mode == 0o400 # Read owner |
| |
| def test_sysfs_file_ownership(self, socket): |
| folder = self.get_dev_folder(socket) |
| |
| st = os.stat(folder + "guid") |
| assert st.st_uid == 0 |
| assert st.st_gid == 0 |
| |
| st = os.stat(folder + "registers") |
| assert st.st_uid == 0 |
| assert st.st_gid == 0 |
| |
| st = os.stat(folder + "provision_akc") |
| assert st.st_uid == 0 |
| assert st.st_gid == 0 |
| |
| st = os.stat(folder + "provision_cap") |
| assert st.st_uid == 0 |
| assert st.st_gid == 0 |
| |
| st = os.stat(folder + "state_certificate") |
| assert st.st_uid == 0 |
| assert st.st_gid == 0 |
| |
| def test_sysfs_file_sizes(self, socket): |
| folder = self.get_dev_folder(socket) |
| |
| if self.read_value(folder + "guid") == GUID: |
| st = os.stat(folder + "registers") |
| assert st.st_size == 72 |
| |
| st = os.stat(folder + "provision_akc") |
| assert st.st_size == 1024 |
| |
| st = os.stat(folder + "provision_cap") |
| assert st.st_size == 1024 |
| |
| st = os.stat(folder + "state_certificate") |
| assert st.st_size == 4096 |
| |
| def test_no_seek_allowed(self, socket): |
| folder = self.get_dev_folder(socket) |
| rand_file = bytes(os.urandom(8)) |
| |
| f = open(folder + "provision_cap", "wb", 0) |
| f.seek(1) |
| with pytest.raises(OSError) as error: |
| f.write(rand_file) |
| assert error.value.errno == errno.ESPIPE |
| f.close() |
| |
| f = open(folder + "provision_akc", "wb", 0) |
| f.seek(1) |
| with pytest.raises(OSError) as error: |
| f.write(rand_file) |
| assert error.value.errno == errno.ESPIPE |
| f.close() |
| |
| def test_registers_seek(self, socket): |
| folder = self.get_dev_folder(socket) |
| |
| # Check that the value read from an offset of the entire |
| # file is none-zero and the same as the value read |
| # from seeking to the same location |
| f = open(folder + "registers", "rb") |
| data = f.read() |
| f.seek(64) |
| id = f.read() |
| assert id != bytes(0) |
| assert data[64:] == id |
| f.close() |
| |
| @pytest.mark.parametrize('socket', range(0, NUM_SOCKETS)) |
| class TestSDSiMailboxCmdsClass: |
| def test_provision_akc_eoverflow_1017_bytes(self, socket): |
| |
| # The buffer for writes is 1k, of with 8 bytes must be |
| # reserved for the command, leaving 1016 bytes max. |
| # Check that we get an overflow error for 1017 bytes. |
| node = get_dev_file_path(socket, "provision_akc") |
| rand_file = bytes(os.urandom(1017)) |
| |
| f = open(node, 'wb', 0) |
| with pytest.raises(OSError) as error: |
| f.write(rand_file) |
| assert error.value.errno == errno.EOVERFLOW |
| f.close() |
| |
| @pytest.mark.parametrize('socket', range(0, NUM_SOCKETS)) |
| class TestSdsiDriverLocksClass: |
| def test_enodev_when_pci_device_removed(self, socket): |
| node = get_dev_file_path(socket, "provision_akc") |
| dev_name = DEV_PREFIX + '.' + str(socket) |
| driver_dir = CLASS_DIR + '/' + dev_name + "/driver/" |
| rand_file = bytes(os.urandom(8)) |
| |
| f = open(node, 'wb', 0) |
| g = open(node, 'wb', 0) |
| |
| with open(driver_dir + 'unbind', 'w') as k: |
| print(dev_name, file = k) |
| |
| with pytest.raises(OSError) as error: |
| f.write(rand_file) |
| assert error.value.errno == errno.ENODEV |
| |
| with pytest.raises(OSError) as error: |
| g.write(rand_file) |
| assert error.value.errno == errno.ENODEV |
| |
| f.close() |
| g.close() |
| |
| # Short wait needed to allow file to close before pulling driver |
| sleep(1) |
| |
| p = subprocess.Popen(('modprobe', '-r', 'intel_sdsi')) |
| p.wait() |
| p = subprocess.Popen(('modprobe', '-r', 'intel_vsec')) |
| p.wait() |
| p = subprocess.Popen(('modprobe', 'intel_vsec')) |
| p.wait() |
| |
| # Short wait needed to allow driver time to get inserted |
| # before continuing tests |
| sleep(1) |
| |
| def test_memory_leak(self, socket): |
| if not kmemleak_enabled(): |
| pytest.skip("kmemleak not enabled in kernel") |
| |
| dev_name = DEV_PREFIX + '.' + str(socket) |
| driver_dir = CLASS_DIR + '/' + dev_name + "/driver/" |
| |
| with open(driver_dir + 'unbind', 'w') as k: |
| print(dev_name, file = k) |
| |
| sleep(1) |
| |
| subprocess.check_output(('modprobe', '-r', 'intel_sdsi')) |
| subprocess.check_output(('modprobe', '-r', 'intel_vsec')) |
| |
| with open('/sys/kernel/debug/kmemleak', 'w') as f: |
| print('scan', file = f) |
| sleep(5) |
| |
| assert os.stat('/sys/kernel/debug/kmemleak').st_size == 0 |
| |
| subprocess.check_output(('modprobe', 'intel_vsec')) |
| sleep(1) |