Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: drivers/s390x: Add uvdevice tests

Adds some selftests to test ioctl error paths of the uv-uapi.
The Kconfig S390_UV_UAPI must be selected and the Ultravisor facility
must be available. The test can be executed by non-root, however, the
uvdevice special file /dev/uv must be accessible for reading and
writing which may imply root privileges.

./test-uv-device
TAP version 13
1..6
# Starting 6 tests from 3 test cases.
# RUN uvio_fixture.att.fault_ioctl_arg ...
# OK uvio_fixture.att.fault_ioctl_arg
ok 1 uvio_fixture.att.fault_ioctl_arg
# RUN uvio_fixture.att.fault_uvio_arg ...
# OK uvio_fixture.att.fault_uvio_arg
ok 2 uvio_fixture.att.fault_uvio_arg
# RUN uvio_fixture.att.inval_ioctl_cb ...
# OK uvio_fixture.att.inval_ioctl_cb
ok 3 uvio_fixture.att.inval_ioctl_cb
# RUN uvio_fixture.att.inval_ioctl_cmd ...
# OK uvio_fixture.att.inval_ioctl_cmd
ok 4 uvio_fixture.att.inval_ioctl_cmd
# RUN attest_fixture.att_inval_request ...
# OK attest_fixture.att_inval_request
ok 5 attest_fixture.att_inval_request
# RUN attest_fixture.att_inval_addr ...
# OK attest_fixture.att_inval_addr
ok 6 attest_fixture.att_inval_addr
# PASSED: 6 / 6 tests passed.
# Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Message-Id: <20220510144724.3321985-3-seiden@linux.ibm.com>
Link: https://lore.kernel.org/kvm/20220510144724.3321985-3-seiden@linux.ibm.com/
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>

authored by

Steffen Eiden and committed by
Janosch Frank
cbac9242 4689752c

+302
+1
MAINTAINERS
··· 10784 10784 F: arch/s390/kvm/ 10785 10785 F: arch/s390/mm/gmap.c 10786 10786 F: drivers/s390/char/uvdevice.c 10787 + F: tools/testing/selftests/drivers/s390x/uvdevice/ 10787 10788 F: tools/testing/selftests/kvm/*/s390x/ 10788 10789 F: tools/testing/selftests/kvm/s390x/ 10789 10790
+1
tools/testing/selftests/Makefile
··· 10 10 TARGETS += cpufreq 11 11 TARGETS += cpu-hotplug 12 12 TARGETS += drivers/dma-buf 13 + TARGETS += drivers/s390x/uvdevice 13 14 TARGETS += efivarfs 14 15 TARGETS += exec 15 16 TARGETS += filesystems
+1
tools/testing/selftests/drivers/.gitignore
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 /dma-buf/udmabuf 3 + /s390x/uvdevice/test_uvdevice
+22
tools/testing/selftests/drivers/s390x/uvdevice/Makefile
··· 1 + include ../../../../../build/Build.include 2 + 3 + UNAME_M := $(shell uname -m) 4 + 5 + ifneq ($(UNAME_M),s390x) 6 + nothing: 7 + .PHONY: all clean run_tests install 8 + .SILENT: 9 + else 10 + 11 + TEST_GEN_PROGS := test_uvdevice 12 + 13 + top_srcdir ?= ../../../../../.. 14 + KSFT_KHDR_INSTALL := 1 15 + khdr_dir = $(top_srcdir)/usr/include 16 + LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/$(ARCH)/include 17 + 18 + CFLAGS += -Wall -Werror -static -I$(khdr_dir) -I$(LINUX_TOOL_ARCH_INCLUDE) 19 + 20 + include ../../../lib.mk 21 + 22 + endif
+1
tools/testing/selftests/drivers/s390x/uvdevice/config
··· 1 + CONFIG_S390_UV_UAPI=y
+276
tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c
··· 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 21 + FIXTURE(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 + 28 + FIXTURE_VARIANT(uvio_fixture) { 29 + unsigned long ioctl_cmd; 30 + uint32_t arg_size; 31 + }; 32 + 33 + FIXTURE_VARIANT_ADD(uvio_fixture, att) { 34 + .ioctl_cmd = UVIO_IOCTL_ATT, 35 + .arg_size = sizeof(struct uvio_attest), 36 + }; 37 + 38 + FIXTURE_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 + 48 + FIXTURE_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 + 55 + TEST_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 + 70 + TEST_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 + */ 91 + TEST_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 + 126 + TEST_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 + 146 + struct test_attest_buffer { 147 + uint8_t arcb[0x180]; 148 + uint8_t meas[64]; 149 + uint8_t add[32]; 150 + }; 151 + 152 + FIXTURE(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 + 160 + FIXTURE_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 + 179 + FIXTURE_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 + 186 + static 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 + */ 212 + TEST_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 + 234 + static 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 + 253 + TEST_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 + 260 + static void __attribute__((constructor)) __constructor_order_last(void) 261 + { 262 + if (!__constructor_order) 263 + __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD; 264 + } 265 + 266 + int 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 + }