1*3521e43fSIngo Weinhold /*
2*3521e43fSIngo Weinhold * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3*3521e43fSIngo Weinhold * Distributed under the terms of the MIT License.
4*3521e43fSIngo Weinhold */
5*3521e43fSIngo Weinhold
6*3521e43fSIngo Weinhold #include <errno.h>
7*3521e43fSIngo Weinhold #include <limits.h>
8*3521e43fSIngo Weinhold #include <signal.h>
9*3521e43fSIngo Weinhold #include <stdint.h>
10*3521e43fSIngo Weinhold #include <stdio.h>
11*3521e43fSIngo Weinhold #include <stdlib.h>
12*3521e43fSIngo Weinhold #include <signal.h>
13*3521e43fSIngo Weinhold #include <string.h>
14*3521e43fSIngo Weinhold #include <sys/mman.h>
15*3521e43fSIngo Weinhold
16*3521e43fSIngo Weinhold
17*3521e43fSIngo Weinhold #ifndef PAGE_SIZE
18*3521e43fSIngo Weinhold # define PAGE_SIZE 4096
19*3521e43fSIngo Weinhold #endif
20*3521e43fSIngo Weinhold
21*3521e43fSIngo Weinhold
22*3521e43fSIngo Weinhold static const size_t kMapChunkSize = 4 * PAGE_SIZE;
23*3521e43fSIngo Weinhold static const size_t kTestSize = 256 * PAGE_SIZE;
24*3521e43fSIngo Weinhold
25*3521e43fSIngo Weinhold static int64_t sHandledSignals = 0;
26*3521e43fSIngo Weinhold
27*3521e43fSIngo Weinhold static uint8_t* sMappedBase;
28*3521e43fSIngo Weinhold static size_t sMappedSize;
29*3521e43fSIngo Weinhold static uint8_t* sTouchedAddress;
30*3521e43fSIngo Weinhold
31*3521e43fSIngo Weinhold
32*3521e43fSIngo Weinhold static void
signal_handler(int signal)33*3521e43fSIngo Weinhold signal_handler(int signal)
34*3521e43fSIngo Weinhold {
35*3521e43fSIngo Weinhold sHandledSignals++;
36*3521e43fSIngo Weinhold
37*3521e43fSIngo Weinhold //printf("SIGSEGV at %p\n", sTouchedAddress);
38*3521e43fSIngo Weinhold
39*3521e43fSIngo Weinhold // protect the last page of the current allocation writable
40*3521e43fSIngo Weinhold if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE,
41*3521e43fSIngo Weinhold PROT_READ | PROT_WRITE) < 0) {
42*3521e43fSIngo Weinhold fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno));
43*3521e43fSIngo Weinhold exit(1);
44*3521e43fSIngo Weinhold }
45*3521e43fSIngo Weinhold
46*3521e43fSIngo Weinhold // allocate the next chunk
47*3521e43fSIngo Weinhold void* mappedAddress = mmap(sMappedBase + sMappedSize, kMapChunkSize,
48*3521e43fSIngo Weinhold PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
49*3521e43fSIngo Weinhold if (mappedAddress == MAP_FAILED) {
50*3521e43fSIngo Weinhold fprintf(stderr, "SIGSEGV: mmap() failed: %s\n", strerror(errno));
51*3521e43fSIngo Weinhold exit(1);
52*3521e43fSIngo Weinhold }
53*3521e43fSIngo Weinhold
54*3521e43fSIngo Weinhold printf("mapped %d bytes at %p\n", (int)kMapChunkSize, mappedAddress);
55*3521e43fSIngo Weinhold
56*3521e43fSIngo Weinhold sMappedSize += kMapChunkSize;
57*3521e43fSIngo Weinhold
58*3521e43fSIngo Weinhold // map the last page read-only
59*3521e43fSIngo Weinhold if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ)
60*3521e43fSIngo Weinhold < 0) {
61*3521e43fSIngo Weinhold fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno));
62*3521e43fSIngo Weinhold exit(1);
63*3521e43fSIngo Weinhold }
64*3521e43fSIngo Weinhold }
65*3521e43fSIngo Weinhold
66*3521e43fSIngo Weinhold
67*3521e43fSIngo Weinhold int
main()68*3521e43fSIngo Weinhold main()
69*3521e43fSIngo Weinhold {
70*3521e43fSIngo Weinhold // install signal handler
71*3521e43fSIngo Weinhold if (signal(SIGSEGV, signal_handler) == SIG_ERR) {
72*3521e43fSIngo Weinhold fprintf(stderr, "Error: Failed to install signal handler: %s\n",
73*3521e43fSIngo Weinhold strerror(errno));
74*3521e43fSIngo Weinhold exit(1);
75*3521e43fSIngo Weinhold }
76*3521e43fSIngo Weinhold
77*3521e43fSIngo Weinhold // Map the complete test size plus one chunk and unmap all but the first
78*3521e43fSIngo Weinhold // chunk again, so no other memory gets into the way, when we mmap() the
79*3521e43fSIngo Weinhold // other chunks with MAP_FIXED.
80*3521e43fSIngo Weinhold sMappedBase = (uint8_t*)mmap(NULL, kTestSize + kMapChunkSize,
81*3521e43fSIngo Weinhold PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
82*3521e43fSIngo Weinhold if (sMappedBase == MAP_FAILED) {
83*3521e43fSIngo Weinhold fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
84*3521e43fSIngo Weinhold return 1;
85*3521e43fSIngo Weinhold }
86*3521e43fSIngo Weinhold munmap(sMappedBase + kMapChunkSize, kTestSize);
87*3521e43fSIngo Weinhold
88*3521e43fSIngo Weinhold sMappedSize = kMapChunkSize;
89*3521e43fSIngo Weinhold
90*3521e43fSIngo Weinhold printf("mapped %d bytes at %p\n", (int)sMappedSize, sMappedBase);
91*3521e43fSIngo Weinhold
92*3521e43fSIngo Weinhold if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ)
93*3521e43fSIngo Weinhold < 0) {
94*3521e43fSIngo Weinhold fprintf(stderr, "mprotect() failed: %s\n", strerror(errno));
95*3521e43fSIngo Weinhold return 1;
96*3521e43fSIngo Weinhold }
97*3521e43fSIngo Weinhold
98*3521e43fSIngo Weinhold for (int i = 0; i < 256 * PAGE_SIZE; i++) {
99*3521e43fSIngo Weinhold sTouchedAddress = sMappedBase + i;
100*3521e43fSIngo Weinhold *sTouchedAddress = 1;
101*3521e43fSIngo Weinhold }
102*3521e43fSIngo Weinhold
103*3521e43fSIngo Weinhold printf("test finished successfully!\n");
104*3521e43fSIngo Weinhold
105*3521e43fSIngo Weinhold return 0;
106*3521e43fSIngo Weinhold }
107