The Pedigree Project 0.1
sysinfo-contract-test/main.c
1#define _GNU_SOURCE
2#include <errno.h>
3#include <stddef.h>
4#include <stdint.h>
5#include <stdio.h>
6#include <string.h>
7#include <time.h>
8#include <unistd.h>
9
10#include <sys/mman.h>
11#include <sys/sysinfo.h>
12#include <sys/wait.h>
13
14#define CHECK(condition) \
15 do { \
16 if (!(condition)) { \
17 fprintf(stderr, "SYSINFO-CONTRACT: line=%d errno=%d\n", __LINE__, errno); \
18 goto fail; \
19 } \
20 } while (0)
21
22static uint64_t seconds(void) {
23 struct timespec now;
24 return clock_gettime(CLOCK_MONOTONIC, &now) ? UINT64_MAX : (uint64_t)now.tv_sec;
25}
26
27int main(void) {
28 struct sysinfo first, second;
29 int result = 1, gates[2] = {-1, -1};
30 pid_t child = -1;
31 const long page = sysconf(_SC_PAGESIZE);
32 void* boundary = MAP_FAILED;
33 void* memory = MAP_FAILED;
34 CHECK(page >= 112);
35 _Static_assert(offsetof(struct sysinfo, mem_unit) == 104, "amd64 sysinfo prefix");
36 memset(&first, 0xa5, sizeof(first));
37 const uint64_t before = seconds();
38 CHECK(sysinfo(&first) == 0 && first.mem_unit == 1 && first.procs > 0);
39 const uint64_t after = seconds();
40 CHECK(first.totalram > 0 && first.freeram <= first.totalram && first.freeswap <= first.totalswap);
41 CHECK(before != UINT64_MAX && after != UINT64_MAX);
42 CHECK(first.uptime >= before && first.uptime <= after + 1);
43 for (size_t i = 112; i < sizeof(first); ++i)
44 CHECK(((const unsigned char*)&first)[i] == 0xa5);
45 errno = 0;
46 CHECK(sysinfo(NULL) == -1 && errno == EFAULT);
47 boundary = mmap(NULL, 2 * page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
48 CHECK(boundary != MAP_FAILED);
49 CHECK(mprotect((char*)boundary + page, page, PROT_NONE) == 0);
50 CHECK(sysinfo((struct sysinfo*)((char*)boundary + page - 112)) == 0);
51 errno = 0;
52 CHECK(sysinfo((struct sysinfo*)((char*)boundary + page - 111)) == -1 && errno == EFAULT);
53 CHECK(mprotect(boundary, page, PROT_READ) == 0);
54 errno = 0;
55 CHECK(sysinfo(boundary) == -1 && errno == EFAULT);
56 memory = mmap(NULL, 32 * page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
57 CHECK(memory != MAP_FAILED);
58 for (size_t offset = 0; offset < 32 * (size_t)page; offset += page)
59 ((volatile unsigned char*)memory)[offset] = 0x5c;
60 CHECK(sysinfo(&second) == 0 && second.totalram == first.totalram &&
61 second.freeram <= second.totalram && second.uptime >= first.uptime);
62 CHECK(pipe(gates) == 0);
63 CHECK(sysinfo(&first) == 0);
64 child = fork();
65 CHECK(child >= 0);
66 if (!child) {
67 close(gates[0]);
68 if (write(gates[1], "r", 1) != 1)
69 _exit(2);
70 const uint64_t started = seconds();
71 if (started == UINT64_MAX)
72 _exit(3);
73 const uint64_t end = started + 7;
74 volatile uint64_t work = 0;
75 while (seconds() < end) {
76 for (unsigned i = 0; i < 100000; ++i)
77 work += i;
78 }
79 _exit(0);
80 }
81 char ready;
82 CHECK(read(gates[0], &ready, 1) == 1);
83 CHECK(sysinfo(&second) == 0 && second.procs > first.procs);
84 struct timespec delay = {6, 0};
85 int slept;
86 do {
87 slept = nanosleep(&delay, &delay);
88 } while (slept && errno == EINTR);
89 CHECK(slept == 0);
90 CHECK(sysinfo(&second) == 0 && second.loads[0] > 0 && second.loads[1] > 0 && second.loads[2] > 0);
91 int status = 0;
92 CHECK(waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 0);
93 child = -1;
94 result = 0;
95fail:
96 if (child > 0)
97 waitpid(child, NULL, 0);
98 if (gates[0] >= 0)
99 close(gates[0]);
100 if (gates[1] >= 0)
101 close(gates[1]);
102 if (boundary != MAP_FAILED)
103 munmap(boundary, 2 * page);
104 if (memory != MAP_FAILED)
105 munmap(memory, 32 * page);
106 puts(result ? "SYSINFO-CONTRACT: FAIL" : "SYSINFO-CONTRACT: PASS");
107 return result;
108}