File: revoke-devmem.c

package info (click to toggle)
ndctl 82-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,460 kB
  • sloc: ansic: 42,027; sh: 3,974; makefile: 28
file content (143 lines) | stat: -rw-r--r-- 3,088 bytes parent folder | download | duplicates (3)
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);
}