linux/tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  selftest for the Ultravisor UAPI device
   4 *
   5 *  Copyright IBM Corp. 2022
   6 *  Author(s): Steffen Eiden <seiden@linux.ibm.com>
   7 */
   8
   9#include <stdint.h>
  10#include <fcntl.h>
  11#include <errno.h>
  12#include <sys/ioctl.h>
  13#include <sys/mman.h>
  14
  15#include <asm/uvdevice.h>
  16
  17#include "../../../kselftest_harness.h"
  18
  19#define UV_PATH  "/dev/uv"
  20#define BUFFER_SIZE 0x200
  21FIXTURE(uvio_fixture) {
  22        int uv_fd;
  23        struct uvio_ioctl_cb uvio_ioctl;
  24        uint8_t buffer[BUFFER_SIZE];
  25        __u64 fault_page;
  26};
  27
  28FIXTURE_VARIANT(uvio_fixture) {
  29        unsigned long ioctl_cmd;
  30        uint32_t arg_size;
  31};
  32
  33FIXTURE_VARIANT_ADD(uvio_fixture, att) {
  34        .ioctl_cmd = UVIO_IOCTL_ATT,
  35        .arg_size = sizeof(struct uvio_attest),
  36};
  37
  38FIXTURE_SETUP(uvio_fixture)
  39{
  40        self->uv_fd = open(UV_PATH, O_ACCMODE);
  41
  42        self->uvio_ioctl.argument_addr = (__u64)self->buffer;
  43        self->uvio_ioctl.argument_len = variant->arg_size;
  44        self->fault_page =
  45                (__u64)mmap(NULL, (size_t)getpagesize(), PROT_NONE, MAP_ANONYMOUS, -1, 0);
  46}
  47
  48FIXTURE_TEARDOWN(uvio_fixture)
  49{
  50        if (self->uv_fd)
  51                close(self->uv_fd);
  52        munmap((void *)self->fault_page, (size_t)getpagesize());
  53}
  54
  55TEST_F(uvio_fixture, fault_ioctl_arg)
  56{
  57        int rc, errno_cache;
  58
  59        rc = ioctl(self->uv_fd, variant->ioctl_cmd, NULL);
  60        errno_cache = errno;
  61        ASSERT_EQ(rc, -1);
  62        ASSERT_EQ(errno_cache, EFAULT);
  63
  64        rc = ioctl(self->uv_fd, variant->ioctl_cmd, self->fault_page);
  65        errno_cache = errno;
  66        ASSERT_EQ(rc, -1);
  67        ASSERT_EQ(errno_cache, EFAULT);
  68}
  69
  70TEST_F(uvio_fixture, fault_uvio_arg)
  71{
  72        int rc, errno_cache;
  73
  74        self->uvio_ioctl.argument_addr = 0;
  75        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
  76        errno_cache = errno;
  77        ASSERT_EQ(rc, -1);
  78        ASSERT_EQ(errno_cache, EFAULT);
  79
  80        self->uvio_ioctl.argument_addr = self->fault_page;
  81        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
  82        errno_cache = errno;
  83        ASSERT_EQ(rc, -1);
  84        ASSERT_EQ(errno_cache, EFAULT);
  85}
  86
  87/*
  88 * Test to verify that IOCTLs with invalid values in the ioctl_control block
  89 * are rejected.
  90 */
  91TEST_F(uvio_fixture, inval_ioctl_cb)
  92{
  93        int rc, errno_cache;
  94
  95        self->uvio_ioctl.argument_len = 0;
  96        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
  97        errno_cache = errno;
  98        ASSERT_EQ(rc, -1);
  99        ASSERT_EQ(errno_cache, EINVAL);
 100
 101        self->uvio_ioctl.argument_len = (uint32_t)-1;
 102        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
 103        errno_cache = errno;
 104        ASSERT_EQ(rc, -1);
 105        ASSERT_EQ(errno_cache, EINVAL);
 106        self->uvio_ioctl.argument_len = variant->arg_size;
 107
 108        self->uvio_ioctl.flags = (uint32_t)-1;
 109        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
 110        errno_cache = errno;
 111        ASSERT_EQ(rc, -1);
 112        ASSERT_EQ(errno_cache, EINVAL);
 113        self->uvio_ioctl.flags = 0;
 114
 115        memset(self->uvio_ioctl.reserved14, 0xff, sizeof(self->uvio_ioctl.reserved14));
 116        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
 117        errno_cache = errno;
 118        ASSERT_EQ(rc, -1);
 119        ASSERT_EQ(errno_cache, EINVAL);
 120
 121        memset(&self->uvio_ioctl, 0x11, sizeof(self->uvio_ioctl));
 122        rc = ioctl(self->uv_fd, variant->ioctl_cmd, &self->uvio_ioctl);
 123        ASSERT_EQ(rc, -1);
 124}
 125
 126TEST_F(uvio_fixture, inval_ioctl_cmd)
 127{
 128        int rc, errno_cache;
 129        uint8_t nr = _IOC_NR(variant->ioctl_cmd);
 130        unsigned long cmds[] = {
 131                _IOWR('a', nr, struct uvio_ioctl_cb),
 132                _IOWR(UVIO_TYPE_UVC, nr, int),
 133                _IO(UVIO_TYPE_UVC, nr),
 134                _IOR(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb),
 135                _IOW(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb),
 136        };
 137
 138        for (size_t i = 0; i < ARRAY_SIZE(cmds); i++) {
 139                rc = ioctl(self->uv_fd, cmds[i], &self->uvio_ioctl);
 140                errno_cache = errno;
 141                ASSERT_EQ(rc, -1);
 142                ASSERT_EQ(errno_cache, ENOTTY);
 143        }
 144}
 145
 146struct test_attest_buffer {
 147        uint8_t arcb[0x180];
 148        uint8_t meas[64];
 149        uint8_t add[32];
 150};
 151
 152FIXTURE(attest_fixture) {
 153        int uv_fd;
 154        struct uvio_ioctl_cb uvio_ioctl;
 155        struct uvio_attest uvio_attest;
 156        struct test_attest_buffer attest_buffer;
 157        __u64 fault_page;
 158};
 159
 160FIXTURE_SETUP(attest_fixture)
 161{
 162        self->uv_fd = open(UV_PATH, O_ACCMODE);
 163
 164        self->uvio_ioctl.argument_addr = (__u64)&self->uvio_attest;
 165        self->uvio_ioctl.argument_len = sizeof(self->uvio_attest);
 166
 167        self->uvio_attest.arcb_addr = (__u64)&self->attest_buffer.arcb;
 168        self->uvio_attest.arcb_len = sizeof(self->attest_buffer.arcb);
 169
 170        self->uvio_attest.meas_addr = (__u64)&self->attest_buffer.meas;
 171        self->uvio_attest.meas_len = sizeof(self->attest_buffer.meas);
 172
 173        self->uvio_attest.add_data_addr = (__u64)&self->attest_buffer.add;
 174        self->uvio_attest.add_data_len = sizeof(self->attest_buffer.add);
 175        self->fault_page =
 176                (__u64)mmap(NULL, (size_t)getpagesize(), PROT_NONE, MAP_ANONYMOUS, -1, 0);
 177}
 178
 179FIXTURE_TEARDOWN(attest_fixture)
 180{
 181        if (self->uv_fd)
 182                close(self->uv_fd);
 183        munmap((void *)self->fault_page, (size_t)getpagesize());
 184}
 185
 186static void att_inval_sizes_test(uint32_t *size, uint32_t max_size, bool test_zero,
 187                                 struct __test_metadata *_metadata,
 188                                 FIXTURE_DATA(attest_fixture) *self)
 189{
 190        int rc, errno_cache;
 191        uint32_t tmp = *size;
 192
 193        if (test_zero) {
 194                *size = 0;
 195                rc = ioctl(self->uv_fd, UVIO_IOCTL_ATT, &self->uvio_ioctl);
 196                errno_cache = errno;
 197                ASSERT_EQ(rc, -1);
 198                ASSERT_EQ(errno_cache, EINVAL);
 199        }
 200        *size = max_size + 1;
 201        rc = ioctl(self->uv_fd, UVIO_IOCTL_ATT, &self->uvio_ioctl);
 202        errno_cache = errno;
 203        ASSERT_EQ(rc, -1);
 204        ASSERT_EQ(errno_cache, EINVAL);
 205        *size = tmp;
 206}
 207
 208/*
 209 * Test to verify that attestation IOCTLs with invalid values in the UVIO
 210 * attestation control block are rejected.
 211 */
 212TEST_F(attest_fixture, att_inval_request)
 213{
 214        int rc, errno_cache;
 215
 216        att_inval_sizes_test(&self->uvio_attest.add_data_len, UVIO_ATT_ADDITIONAL_MAX_LEN,
 217                             false, _metadata, self);
 218        att_inval_sizes_test(&self->uvio_attest.meas_len, UVIO_ATT_MEASUREMENT_MAX_LEN,
 219                             true, _metadata, self);
 220        att_inval_sizes_test(&self->uvio_attest.arcb_len, UVIO_ATT_ARCB_MAX_LEN,
 221                             true, _metadata, self);
 222
 223        self->uvio_attest.reserved136 = (uint16_t)-1;
 224        rc = ioctl(self->uv_fd, UVIO_IOCTL_ATT, &self->uvio_ioctl);
 225        errno_cache = errno;
 226        ASSERT_EQ(rc, -1);
 227        ASSERT_EQ(errno_cache, EINVAL);
 228
 229        memset(&self->uvio_attest, 0x11, sizeof(self->uvio_attest));
 230        rc = ioctl(self->uv_fd, UVIO_IOCTL_ATT, &self->uvio_ioctl);
 231        ASSERT_EQ(rc, -1);
 232}
 233
 234static void att_inval_addr_test(__u64 *addr, struct __test_metadata *_metadata,
 235                                FIXTURE_DATA(attest_fixture) *self)
 236{
 237        int rc, errno_cache;
 238        __u64 tmp = *addr;
 239
 240        *addr = 0;
 241        rc = ioctl(self->uv_fd, UVIO_IOCTL_ATT, &self->uvio_ioctl);
 242        errno_cache = errno;
 243        ASSERT_EQ(rc, -1);
 244        ASSERT_EQ(errno_cache, EFAULT);
 245        *addr = self->fault_page;
 246        rc = ioctl(self->uv_fd, UVIO_IOCTL_ATT, &self->uvio_ioctl);
 247        errno_cache = errno;
 248        ASSERT_EQ(rc, -1);
 249        ASSERT_EQ(errno_cache, EFAULT);
 250        *addr = tmp;
 251}
 252
 253TEST_F(attest_fixture, att_inval_addr)
 254{
 255        att_inval_addr_test(&self->uvio_attest.arcb_addr, _metadata, self);
 256        att_inval_addr_test(&self->uvio_attest.add_data_addr, _metadata, self);
 257        att_inval_addr_test(&self->uvio_attest.meas_addr, _metadata, self);
 258}
 259
 260static void __attribute__((constructor)) __constructor_order_last(void)
 261{
 262        if (!__constructor_order)
 263                __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
 264}
 265
 266int main(int argc, char **argv)
 267{
 268        int fd = open(UV_PATH, O_ACCMODE);
 269
 270        if (fd < 0)
 271                ksft_exit_skip("No uv-device or cannot access " UV_PATH  "\n"
 272                               "Enable CONFIG_S390_UV_UAPI and check the access rights on "
 273                               UV_PATH ".\n");
 274        close(fd);
 275        return test_harness_run(argc, argv);
 276}
 277