The Pedigree Project 0.1
init-module-contract-test/main.c
1/* Copyright (c) 2026, Pedigree Developers. */
2#define _GNU_SOURCE
3#include <errno.h>
4#include <fcntl.h>
5#include <signal.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11#include <sys/mman.h>
12#include <sys/stat.h>
13#include <sys/syscall.h>
14#include <sys/wait.h>
15
16#define IMAGE_LIMIT (1024U * 1024U)
17static const char module_name[] = "init-module-contract";
18static int loaded;
19
20static long load_module(const void* image, size_t size, const char* parameters) {
21 return syscall(SYS_init_module, image, size, parameters);
22}
23static long unload_module(void) {
24 return syscall(SYS_delete_module, module_name, O_NONBLOCK);
25}
26static int load_error(const void* image, size_t size, const char* parameters, int expected,
27 const char* detail) {
28 errno = 0;
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);
33 if (!result)
34 loaded = 1;
35 return 1;
36 }
37 return 0;
38}
39static int unload_error(int expected, const char* detail) {
40 errno = 0;
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);
45 return 1;
46 }
47 return 0;
48}
49static unsigned char* read_image(const char* path, size_t* size) {
50 int fd = open(path, O_RDONLY);
51 struct stat info;
52 if (fd < 0)
53 return NULL;
54 if (fstat(fd, &info) || info.st_size <= 0 || info.st_size > IMAGE_LIMIT) {
55 close(fd);
56 return NULL;
57 }
58 *size = (size_t)info.st_size;
59 unsigned char* image = malloc(*size);
60 if (!image) {
61 close(fd);
62 return NULL;
63 }
64 size_t copied = 0;
65 while (copied < *size) {
66 ssize_t amount = read(fd, image + copied, *size - copied);
67 if (amount < 0 && errno == EINTR)
68 continue;
69 if (amount <= 0) {
70 free(image);
71 close(fd);
72 return NULL;
73 }
74 copied += (size_t)amount;
75 }
76 close(fd);
77 return image;
78}
79static int credentials(const unsigned char* image, size_t size) {
80 pid_t child = fork();
81 if (!child) {
82 if (setuid(65534))
83 _exit(2);
84 _exit(load_error(image, size, "", EPERM, "unprivileged load") ||
85 unload_error(EPERM, "unprivileged unload"));
86 }
87 int status = 0;
88 pid_t waited;
89 do {
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);
93}
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"))
102 return 1;
103 unsigned char magic = image[0];
104 image[0] = 0;
105 int invalid = load_error(image, size, "", ENOEXEC, "invalid ELF magic");
106 image[0] = magic;
107 if (invalid)
108 return 1;
109 long page = sysconf(_SC_PAGESIZE);
110 if (page <= 0)
111 return 1;
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)
115 return 1;
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)
121 return 1;
122 puts("INIT-MODULE-CONTRACT: PASS input-copy-policy");
123
124 errno = 0;
125 if (load_module(image, size, "")) {
126 fprintf(stderr, "INIT-MODULE-CONTRACT: FAIL load errno=%d\n", errno);
127 return 1;
128 }
129 loaded = 1;
130 if (errno || load_error(image, size, "", EEXIST, "duplicate live module"))
131 return 1;
132 puts("INIT-MODULE-CONTRACT: PASS load-duplicate");
133 if (credentials(image, size))
134 return 1;
135 puts("INIT-MODULE-CONTRACT: PASS credentials");
136 if (unload_module())
137 return 1;
138 loaded = 0;
139 if (unload_error(ENOENT, "repeated unload"))
140 return 1;
141 puts("INIT-MODULE-CONTRACT: PASS unload");
142
143 if (load_module(image, size, ""))
144 return 1;
145 loaded = 1;
146 if (unload_module())
147 return 1;
148 loaded = 0;
149 puts("INIT-MODULE-CONTRACT: PASS reload");
150 return 0;
151}
152int main(int argc, char** argv) {
153 setvbuf(stdout, NULL, _IONBF, 0);
154 alarm(60);
155 puts("INIT-MODULE-CONTRACT: BEGIN");
156 const char* path = argc == 2 ? argv[1] : "/tests/init-module-contract-fixture.o";
157 size_t size = 0;
158 unsigned char* image = geteuid() == 0 && argc <= 2 ? read_image(path, &size) : NULL;
159 if (!image) {
160 fprintf(stderr, "INIT-MODULE-CONTRACT: FAIL requires root and readable fixture %s\n", path);
161 puts("INIT-MODULE-CONTRACT: END FAIL");
162 return 1;
163 }
164 int failed = run(image, size);
165 if (loaded) {
166 if (unload_module())
167 fprintf(stderr, "INIT-MODULE-CONTRACT: cleanup unload failed errno=%d\n", errno);
168 }
169 free(image);
170 puts(failed ? "INIT-MODULE-CONTRACT: END FAIL" : "INIT-MODULE-CONTRACT: END PASS");
171 return failed;
172}