cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdsi_test.py (7229B)


      1#!/usr/bin/env python3
      2# SPDX-License-Identifier: GPL-2.0
      3
      4from struct import pack
      5from time import sleep
      6
      7import errno
      8import glob
      9import os
     10import subprocess
     11
     12try:
     13    import pytest
     14except ImportError:
     15    print("Unable to import pytest python module.")
     16    print("\nIf not already installed, you may do so with:")
     17    print("\t\tpip3 install pytest")
     18    exit(1)
     19
     20SOCKETS = glob.glob('/sys/bus/auxiliary/devices/intel_vsec.sdsi.*')
     21NUM_SOCKETS = len(SOCKETS)
     22
     23MODULE_NAME = 'intel_sdsi'
     24DEV_PREFIX = 'intel_vsec.sdsi'
     25CLASS_DIR = '/sys/bus/auxiliary/devices'
     26GUID = "0x6dd191"
     27
     28def read_bin_file(file):
     29    with open(file, mode='rb') as f:
     30        content = f.read()
     31    return content
     32
     33def get_dev_file_path(socket, file):
     34    return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' + file
     35
     36def kmemleak_enabled():
     37    kmemleak = "/sys/kernel/debug/kmemleak"
     38    return os.path.isfile(kmemleak)
     39
     40class TestSDSiDriver:
     41    def test_driver_loaded(self):
     42        lsmod_p = subprocess.Popen(('lsmod'), stdout=subprocess.PIPE)
     43        result = subprocess.check_output(('grep', '-q', MODULE_NAME), stdin=lsmod_p.stdout)
     44
     45@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
     46class TestSDSiFilesClass:
     47
     48    def read_value(self, file):
     49        f = open(file, "r")
     50        value = f.read().strip("\n")
     51        return value
     52
     53    def get_dev_folder(self, socket):
     54        return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/'
     55
     56    def test_sysfs_files_exist(self, socket):
     57        folder = self.get_dev_folder(socket)
     58        print (folder)
     59        assert os.path.isfile(folder + "guid") == True
     60        assert os.path.isfile(folder + "provision_akc") == True
     61        assert os.path.isfile(folder + "provision_cap") == True
     62        assert os.path.isfile(folder + "state_certificate") == True
     63        assert os.path.isfile(folder + "registers") == True
     64
     65    def test_sysfs_file_permissions(self, socket):
     66        folder = self.get_dev_folder(socket)
     67        mode = os.stat(folder + "guid").st_mode & 0o777
     68        assert mode == 0o444    # Read all
     69        mode = os.stat(folder + "registers").st_mode & 0o777
     70        assert mode == 0o400    # Read owner
     71        mode = os.stat(folder + "provision_akc").st_mode & 0o777
     72        assert mode == 0o200    # Read owner
     73        mode = os.stat(folder + "provision_cap").st_mode & 0o777
     74        assert mode == 0o200    # Read owner
     75        mode = os.stat(folder + "state_certificate").st_mode & 0o777
     76        assert mode == 0o400    # Read owner
     77
     78    def test_sysfs_file_ownership(self, socket):
     79        folder = self.get_dev_folder(socket)
     80
     81        st = os.stat(folder + "guid")
     82        assert st.st_uid == 0
     83        assert st.st_gid == 0
     84
     85        st = os.stat(folder + "registers")
     86        assert st.st_uid == 0
     87        assert st.st_gid == 0
     88
     89        st = os.stat(folder + "provision_akc")
     90        assert st.st_uid == 0
     91        assert st.st_gid == 0
     92
     93        st = os.stat(folder + "provision_cap")
     94        assert st.st_uid == 0
     95        assert st.st_gid == 0
     96
     97        st = os.stat(folder + "state_certificate")
     98        assert st.st_uid == 0
     99        assert st.st_gid == 0
    100
    101    def test_sysfs_file_sizes(self, socket):
    102        folder = self.get_dev_folder(socket)
    103
    104        if self.read_value(folder + "guid") == GUID:
    105            st = os.stat(folder + "registers")
    106            assert st.st_size == 72
    107
    108        st = os.stat(folder + "provision_akc")
    109        assert st.st_size == 1024
    110
    111        st = os.stat(folder + "provision_cap")
    112        assert st.st_size == 1024
    113
    114        st = os.stat(folder + "state_certificate")
    115        assert st.st_size == 4096
    116
    117    def test_no_seek_allowed(self, socket):
    118        folder = self.get_dev_folder(socket)
    119        rand_file = bytes(os.urandom(8))
    120
    121        f = open(folder + "provision_cap", "wb", 0)
    122        f.seek(1)
    123        with pytest.raises(OSError) as error:
    124            f.write(rand_file)
    125        assert error.value.errno == errno.ESPIPE
    126        f.close()
    127
    128        f = open(folder + "provision_akc", "wb", 0)
    129        f.seek(1)
    130        with pytest.raises(OSError) as error:
    131            f.write(rand_file)
    132        assert error.value.errno == errno.ESPIPE
    133        f.close()
    134
    135    def test_registers_seek(self, socket):
    136        folder = self.get_dev_folder(socket)
    137
    138        # Check that the value read from an offset of the entire
    139        # file is none-zero and the same as the value read
    140        # from seeking to the same location
    141        f = open(folder + "registers", "rb")
    142        data = f.read()
    143        f.seek(64)
    144        id = f.read()
    145        assert id != bytes(0)
    146        assert data[64:] == id
    147        f.close()
    148
    149@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
    150class TestSDSiMailboxCmdsClass:
    151    def test_provision_akc_eoverflow_1017_bytes(self, socket):
    152
    153        # The buffer for writes is 1k, of with 8 bytes must be
    154        # reserved for the command, leaving 1016 bytes max.
    155        # Check that we get an overflow error for 1017 bytes.
    156        node = get_dev_file_path(socket, "provision_akc")
    157        rand_file = bytes(os.urandom(1017))
    158
    159        f = open(node, 'wb', 0)
    160        with pytest.raises(OSError) as error:
    161            f.write(rand_file)
    162        assert error.value.errno == errno.EOVERFLOW
    163        f.close()
    164
    165@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
    166class TestSdsiDriverLocksClass:
    167    def test_enodev_when_pci_device_removed(self, socket):
    168        node = get_dev_file_path(socket, "provision_akc")
    169        dev_name = DEV_PREFIX + '.' + str(socket)
    170        driver_dir = CLASS_DIR + '/' + dev_name + "/driver/"
    171        rand_file = bytes(os.urandom(8))
    172
    173        f = open(node, 'wb', 0)
    174        g = open(node, 'wb', 0)
    175
    176        with open(driver_dir + 'unbind', 'w') as k:
    177            print(dev_name, file = k)
    178
    179        with pytest.raises(OSError) as error:
    180            f.write(rand_file)
    181        assert error.value.errno == errno.ENODEV
    182
    183        with pytest.raises(OSError) as error:
    184            g.write(rand_file)
    185        assert error.value.errno == errno.ENODEV
    186
    187        f.close()
    188        g.close()
    189
    190        # Short wait needed to allow file to close before pulling driver
    191        sleep(1)
    192
    193        p = subprocess.Popen(('modprobe', '-r', 'intel_sdsi'))
    194        p.wait()
    195        p = subprocess.Popen(('modprobe', '-r', 'intel_vsec'))
    196        p.wait()
    197        p = subprocess.Popen(('modprobe', 'intel_vsec'))
    198        p.wait()
    199
    200        # Short wait needed to allow driver time to get inserted
    201        # before continuing tests
    202        sleep(1)
    203
    204    def test_memory_leak(self, socket):
    205        if not kmemleak_enabled():
    206            pytest.skip("kmemleak not enabled in kernel")
    207
    208        dev_name = DEV_PREFIX + '.' + str(socket)
    209        driver_dir = CLASS_DIR + '/' + dev_name + "/driver/"
    210
    211        with open(driver_dir + 'unbind', 'w') as k:
    212            print(dev_name, file = k)
    213
    214        sleep(1)
    215
    216        subprocess.check_output(('modprobe', '-r', 'intel_sdsi'))
    217        subprocess.check_output(('modprobe', '-r', 'intel_vsec'))
    218
    219        with open('/sys/kernel/debug/kmemleak', 'w') as f:
    220            print('scan', file = f)
    221        sleep(5)
    222
    223        assert os.stat('/sys/kernel/debug/kmemleak').st_size == 0
    224
    225        subprocess.check_output(('modprobe', 'intel_vsec'))
    226        sleep(1)