1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Intel Corporation. All rights reserved. */
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <util/size.h>
#include <linux/falloc.h>
#include <linux/version.h>
#include <ndctl/libndctl.h>
#include <ccan/array_size/array_size.h>
#include <ndctl/builtin.h>
#include <test.h>
static sigjmp_buf sj_env;
static void sigbus(int sig, siginfo_t *siginfo, void *d)
{
siglongjmp(sj_env, 1);
}
#define err(fmt, ...) \
fprintf(stderr, "%s: " fmt, __func__, ##__VA_ARGS__)
static int test_devmem(int loglevel, struct ndctl_test *test,
struct ndctl_ctx *ctx)
{
void *buf;
int fd, rc;
struct sigaction act;
unsigned long long resource;
struct ndctl_namespace *ndns;
ndctl_set_log_priority(ctx, loglevel);
/* iostrict devmem started in kernel 4.5 */
if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 5, 0)))
return 77;
ndns = ndctl_get_test_dev(ctx);
if (!ndns) {
err("failed to find suitable namespace\n");
return 77;
}
resource = ndctl_namespace_get_resource(ndns);
if (resource == ULLONG_MAX) {
err("failed to retrieve resource base\n");
return 77;
}
rc = ndctl_namespace_disable(ndns);
if (rc) {
err("failed to disable namespace\n");
return rc;
}
/* establish a devmem mapping of the namespace memory */
fd = open("/dev/mem", O_RDWR);
if (fd < 0) {
err("failed to open /dev/mem: %s\n", strerror(errno));
rc = -errno;
goto out_devmem;
}
buf = mmap(NULL, SZ_2M, PROT_READ|PROT_WRITE, MAP_SHARED, fd, resource);
if (buf == MAP_FAILED) {
err("failed to map /dev/mem: %s\n", strerror(errno));
rc = -errno;
goto out_mmap;
}
/* populate and write, should not fail */
memset(buf, 0, SZ_2M);
memset(&act, 0, sizeof(act));
act.sa_sigaction = sigbus;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGBUS, &act, 0)) {
perror("sigaction");
rc = EXIT_FAILURE;
goto out_sigaction;
}
/* test fault due to devmem revocation */
if (sigsetjmp(sj_env, 1)) {
/* got sigbus, success */
fprintf(stderr, "devmem revoked!\n");
rc = 0;
goto out_sigaction;
}
rc = ndctl_namespace_enable(ndns);
if (rc) {
err("failed to enable namespace\n");
goto out_sigaction;
}
/* write, should sigbus */
memset(buf, 0, SZ_2M);
err("kernel failed to prevent write after namespace enabled\n");
rc = -ENXIO;
out_sigaction:
munmap(buf, SZ_2M);
out_mmap:
close(fd);
out_devmem:
if (ndctl_namespace_enable(ndns) != 0)
err("failed to re-enable namespace\n");
return rc;
}
int main(int argc, char *argv[])
{
struct ndctl_test *test = ndctl_test_new(0);
struct ndctl_ctx *ctx;
int rc;
if (!test) {
fprintf(stderr, "failed to initialize test\n");
return EXIT_FAILURE;
}
rc = ndctl_new(&ctx);
if (rc < 0)
return ndctl_test_result(test, rc);
rc = test_devmem(LOG_DEBUG, test, ctx);
ndctl_unref(ctx);
return ndctl_test_result(test, rc);
}
|