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