271 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * selftest for the Ultravisor UAPI device4 *5 * Copyright IBM Corp. 20226 * 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 0x20021FIXTURE(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 block89 * 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 UVIO210 * 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 260int main(int argc, char **argv)261{262 int fd = open(UV_PATH, O_ACCMODE);263 264 if (fd < 0)265 ksft_exit_skip("No uv-device or cannot access " UV_PATH "\n"266 "Enable CONFIG_S390_UV_UAPI and check the access rights on "267 UV_PATH ".\n");268 close(fd);269 return test_harness_run(argc, argv);270}271