The Pedigree Project 0.1
personality-contract-test/main.c
1#define _GNU_SOURCE
2#include <errno.h>
3#include <pthread.h>
4#include <stdint.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <sys/personality.h>
11#include <sys/utsname.h>
12#include <sys/wait.h>
13
14#define CHECK(condition) \
15 do { \
16 if (!(condition)) { \
17 fprintf(stderr, "PERSONALITY-CONTRACT: line=%d errno=%d\n", __LINE__, errno); \
18 goto fail; \
19 } \
20 } while (0)
21
22static char native_machine[65];
23
24static int selected(int expected, const char* machine) {
25 struct utsname name;
26 return personality(0xffffffffUL) == expected && !uname(&name) && !strcmp(name.machine, machine);
27}
28
29static void* thread_test(void* unused) {
30 (void)unused;
31 if (!selected(PER_LINUX32, "i686"))
32 return (void*)1;
33 if (personality(PER_LINUX) != PER_LINUX32 || !selected(PER_LINUX, native_machine))
34 return (void*)2;
35 return NULL;
36}
37
38int main(int argc, char** argv) {
39 if (argc == 2 && !strcmp(argv[1], "--exec-child"))
40 return selected(PER_LINUX32, "i686") ? 0 : 3;
41 struct utsname name;
42 int result = 1;
43 const int original = personality(0xffffffffUL);
44 CHECK(original >= 0);
45 CHECK(personality(PER_LINUX) == original);
46 CHECK(uname(&name) == 0);
47 memcpy(native_machine, name.machine, sizeof(native_machine));
48 CHECK(personality(PER_LINUX32) == PER_LINUX);
49 CHECK(selected(PER_LINUX32, "i686"));
50 const unsigned long unsupported[] = {PER_BSD,
51 PER_LINUX32 | ADDR_LIMIT_3GB,
52 PER_LINUX | ADDR_NO_RANDOMIZE,
53 PER_LINUX | READ_IMPLIES_EXEC,
54 PER_LINUX | UNAME26,
55 PER_LINUX_FDPIC};
56 for (size_t i = 0; i < sizeof(unsupported) / sizeof(unsupported[0]); ++i) {
57 errno = 0;
58 CHECK(personality(unsupported[i]) == -1 && errno == EINVAL);
59 CHECK(selected(PER_LINUX32, "i686"));
60 }
61 pthread_t thread;
62 void* returned = (void*)9;
63 CHECK(pthread_create(&thread, NULL, thread_test, NULL) == 0);
64 CHECK(pthread_join(thread, &returned) == 0 && returned == NULL);
65 CHECK(selected(PER_LINUX32, "i686"));
66 pid_t child = fork();
67 CHECK(child >= 0);
68 if (!child) {
69 if (!selected(PER_LINUX32, "i686"))
70 _exit(4);
71 execlp(argv[0], argv[0], "--exec-child", (char*)NULL);
72 _exit(5);
73 }
74 int status = 0;
75 CHECK(waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 0);
76 CHECK(personality(PER_LINUX) == PER_LINUX32);
77 CHECK(selected(PER_LINUX, native_machine));
78 result = 0;
79fail:
80 if (original >= 0)
81 personality((unsigned long)original);
82 puts(result ? "PERSONALITY-CONTRACT: FAIL" : "PERSONALITY-CONTRACT: PASS");
83 return result;
84}