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

test_uvdevice.c (7291B)


      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}