13#include <sys/syscall.h>
16#define IMAGE_LIMIT (1024U * 1024U)
17static const char module_name[] =
"init-module-contract";
20static long load_module(
const void* image,
size_t size,
const char* parameters) {
21 return syscall(SYS_init_module, image, size, parameters);
23static long unload_module(
void) {
24 return syscall(SYS_delete_module, module_name, O_NONBLOCK);
26static int load_error(
const void* image,
size_t size,
const char* parameters,
int expected,
29 long result = load_module(image, size, parameters);
30 if (result != -1 || errno != expected) {
31 fprintf(stderr,
"INIT-MODULE-CONTRACT: FAIL %s result=%ld errno=%d expected=%d\n", detail,
32 result, errno, expected);
39static int unload_error(
int expected,
const char* detail) {
41 long result = unload_module();
42 if (result != -1 || errno != expected) {
43 fprintf(stderr,
"INIT-MODULE-CONTRACT: FAIL %s result=%ld errno=%d expected=%d\n", detail,
44 result, errno, expected);
49static unsigned char* read_image(
const char* path,
size_t* size) {
50 int fd = open(path, O_RDONLY);
54 if (fstat(fd, &info) || info.st_size <= 0 || info.st_size > IMAGE_LIMIT) {
58 *size = (size_t)info.st_size;
59 unsigned char* image = malloc(*size);
65 while (copied < *size) {
66 ssize_t amount = read(fd, image + copied, *size - copied);
67 if (amount < 0 && errno == EINTR)
74 copied += (size_t)amount;
79static int credentials(
const unsigned char* image,
size_t size) {
84 _exit(load_error(image, size,
"", EPERM,
"unprivileged load") ||
85 unload_error(EPERM,
"unprivileged unload"));
90 waited = child < 0 ? -1 : waitpid(child, &status, 0);
91 }
while (waited < 0 && errno == EINTR);
92 return child < 0 || waited != child || !WIFEXITED(status) || WEXITSTATUS(status);
94static int run(
unsigned char* image,
size_t size) {
95 if (unload_error(ENOENT,
"fixture unexpectedly boot-loaded") ||
96 load_error(NULL, size,
"", EFAULT,
"null input") ||
97 load_error(image, size, NULL, EFAULT,
"null parameters") ||
98 load_error(image, size,
"unsupported=1", EOPNOTSUPP,
"nonempty parameters") ||
99 load_error(image, 0,
"", ENOEXEC,
"empty image") ||
100 load_error(image, IMAGE_LIMIT + 1,
"", ENOEXEC,
"image bound") ||
101 load_error(image, 16,
"", ENOEXEC,
"truncated header"))
103 unsigned char magic = image[0];
105 int invalid = load_error(image, size,
"", ENOEXEC,
"invalid ELF magic");
109 long page = sysconf(_SC_PAGESIZE);
112 unsigned char* range =
113 mmap(NULL, (
size_t)page * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
114 if (range == MAP_FAILED)
116 memcpy(range + page - 8, image, 8);
117 int copied = mprotect(range + page, (
size_t)page, PROT_NONE) ||
118 load_error(range + page - 8, 16,
"", EFAULT,
"inaccessible input tail");
119 int unmapped = munmap(range, (
size_t)page * 2);
120 if (copied || unmapped)
122 puts(
"INIT-MODULE-CONTRACT: PASS input-copy-policy");
125 if (load_module(image, size,
"")) {
126 fprintf(stderr,
"INIT-MODULE-CONTRACT: FAIL load errno=%d\n", errno);
130 if (errno || load_error(image, size,
"", EEXIST,
"duplicate live module"))
132 puts(
"INIT-MODULE-CONTRACT: PASS load-duplicate");
133 if (credentials(image, size))
135 puts(
"INIT-MODULE-CONTRACT: PASS credentials");
139 if (unload_error(ENOENT,
"repeated unload"))
141 puts(
"INIT-MODULE-CONTRACT: PASS unload");
143 if (load_module(image, size,
""))
149 puts(
"INIT-MODULE-CONTRACT: PASS reload");
152int main(
int argc,
char** argv) {
153 setvbuf(stdout, NULL, _IONBF, 0);
155 puts(
"INIT-MODULE-CONTRACT: BEGIN");
156 const char* path = argc == 2 ? argv[1] :
"/tests/init-module-contract-fixture.o";
158 unsigned char* image = geteuid() == 0 && argc <= 2 ? read_image(path, &size) : NULL;
160 fprintf(stderr,
"INIT-MODULE-CONTRACT: FAIL requires root and readable fixture %s\n", path);
161 puts(
"INIT-MODULE-CONTRACT: END FAIL");
164 int failed = run(image, size);
167 fprintf(stderr,
"INIT-MODULE-CONTRACT: cleanup unload failed errno=%d\n", errno);
170 puts(failed ?
"INIT-MODULE-CONTRACT: END FAIL" :
"INIT-MODULE-CONTRACT: END PASS");