The Pedigree Project 0.1
limits.c
1#define _GNU_SOURCE
2#include <unistd.h>
3
4#include "contract.h"
5#include <sys/mman.h>
6#include <sys/resource.h>
7#include <sys/syscall.h>
8
9int ml_limits(void) {
10 int failed = 0;
11 struct rlimit original, current, request;
12 void* inaccessible = MAP_FAILED;
13 void* readonly = MAP_FAILED;
14 unsigned char* pages = MAP_FAILED;
15 CHECK(getrlimit(RLIMIT_MEMLOCK, &original) == 0);
16 CHECK(original.rlim_cur == 16 * 1024 * 1024 && original.rlim_max == original.rlim_cur);
17 inaccessible = mmap(NULL, ml_page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
18 readonly = mmap(NULL, ml_page, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
19 pages = mmap(NULL, 2 * ml_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
20 CHECK(inaccessible != MAP_FAILED && readonly != MAP_FAILED && pages != MAP_FAILED);
21
22 request = original;
23 request.rlim_cur = 4 * ml_page;
24 CHECK(setrlimit(RLIMIT_MEMLOCK, &request) == 0);
25 CHECK(prlimit(getpid(), RLIMIT_MEMLOCK, NULL, &current) == 0);
26 CHECK(current.rlim_cur == request.rlim_cur && current.rlim_max == request.rlim_max);
27 request.rlim_cur = 3 * ml_page;
28 CHECK(syscall(SYS_setrlimit, RLIMIT_MEMLOCK, &request) == 0);
29 request.rlim_cur = 2 * ml_page;
30 CHECK(prlimit(0, RLIMIT_MEMLOCK, &request, &request) == 0);
31 CHECK(request.rlim_cur == 3 * ml_page);
32 CHECK(getrlimit(RLIMIT_MEMLOCK, &current) == 0 && current.rlim_cur == 2 * ml_page);
33
34 errno = 0;
35 CHECK(setrlimit(RLIMIT_MEMLOCK, inaccessible) == -1 && errno == EFAULT);
36 errno = 0;
37 CHECK(syscall(SYS_setrlimit, RLIMIT_MEMLOCK, inaccessible) == -1 && errno == EFAULT);
38 CHECK(getrlimit(RLIMIT_MEMLOCK, &current) == 0 && current.rlim_cur == 2 * ml_page);
39 request = current;
40 request.rlim_cur = ml_page;
41 errno = 0;
42 CHECK(prlimit(0, RLIMIT_MEMLOCK, &request, readonly) == -1 && errno == EFAULT);
43 CHECK(getrlimit(RLIMIT_MEMLOCK, &current) == 0 && current.rlim_cur == ml_page);
44 errno = 0;
45 CHECK(prlimit(0, RLIMIT_MEMLOCK, NULL, readonly) == -1 && errno == EFAULT);
46 request.rlim_cur = 3 * ml_page;
47 request.rlim_max = 2 * ml_page;
48 errno = 0;
49 CHECK(setrlimit(RLIMIT_MEMLOCK, &request) == -1 && errno == EINVAL);
50 CHECK(getrlimit(RLIMIT_MEMLOCK, &current) == 0 && current.rlim_cur == ml_page);
51
52 request.rlim_cur = request.rlim_max = 2 * ml_page;
53 CHECK(setrlimit(RLIMIT_MEMLOCK, &request) == 0 && ml_unprivileged() == 0);
54 request.rlim_max = 3 * ml_page;
55 errno = 0;
56 CHECK(setrlimit(RLIMIT_MEMLOCK, &request) == -1 && errno == EPERM);
57 CHECK(mlock(pages, ml_page) == 0);
58 CHECK(ml_limit(0) == 0);
59 errno = 0;
60 CHECK(madvise(pages, ml_page, MADV_DONTNEED) == -1 && errno == EINVAL);
61 errno = 0;
62 CHECK(mlock(pages + ml_page, ml_page) == -1 && errno == EPERM);
63 CHECK(munlockall() == 0 && madvise(pages, ml_page, MADV_DONTNEED) == 0);
64 CHECK(ml_limit(ml_page) == 0 && mlock(pages + ml_page, ml_page) == 0);
65out:
66 munlockall();
67 if (pages != MAP_FAILED)
68 munmap(pages, 2 * ml_page);
69 if (readonly != MAP_FAILED)
70 munmap(readonly, ml_page);
71 if (inaccessible != MAP_FAILED)
72 munmap(inaccessible, ml_page);
73 return failed;
74}