• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *    Stack-less Just-In-Time compiler
3  *
4  *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification, are
7  * permitted provided that the following conditions are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright notice, this list of
10  *      conditions and the following disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above copyright notice, this list
13  *      of conditions and the following disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28    This file contains a simple W^X executable memory allocator for POSIX
29    like systems and Windows
30 
31    In *NIX, MAP_ANON is required (that is considered a feature) so make
32    sure to set the right availability macros for your system or the code
33    will fail to build.
34 
35    If your system doesn't support mapping of anonymous pages (ex: IRIX) it
36    is also likely that it doesn't need this allocator and should be using
37    the standard one instead.
38 
39    It allocates a separate map for each code block and may waste a lot of
40    memory, because whatever was requested, will be rounded up to the page
41    size (minimum 4KB, but could be even bigger).
42 
43    It changes the page permissions (RW <-> RX) as needed and therefore, if you
44    will be updating the code after it has been generated, need to make sure to
45    block any concurrent execution, or could result in a SIGBUS, that could
46    even manifest itself at a different address than the one that was being
47    modified.
48 
49    Only use if you are unable to use the regular allocator because of security
50    restrictions and adding exceptions to your application or the system are
51    not possible.
52 */
53 
54 #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
55 	sljit_update_wx_flags((from), (to), (enable_exec))
56 
57 #ifndef _WIN32
58 #include <sys/types.h>
59 #include <sys/mman.h>
60 
61 #ifdef __NetBSD__
62 #if defined(PROT_MPROTECT)
63 #define check_se_protected(ptr, size) (0)
64 #define SLJIT_PROT_WX PROT_MPROTECT(PROT_EXEC)
65 #else /* !PROT_MPROTECT */
66 #ifdef _NETBSD_SOURCE
67 #include <sys/param.h>
68 #else /* !_NETBSD_SOURCE */
69 typedef unsigned int	u_int;
70 #define devmajor_t sljit_s32
71 #endif /* _NETBSD_SOURCE */
72 #include <sys/sysctl.h>
73 #include <unistd.h>
74 
75 #define check_se_protected(ptr, size) netbsd_se_protected()
76 
netbsd_se_protected(void)77 static SLJIT_INLINE int netbsd_se_protected(void)
78 {
79 	int mib[3];
80 	int paxflags;
81 	size_t len = sizeof(paxflags);
82 
83 	mib[0] = CTL_PROC;
84 	mib[1] = getpid();
85 	mib[2] = PROC_PID_PAXFLAGS;
86 
87 	if (SLJIT_UNLIKELY(sysctl(mib, 3, &paxflags, &len, NULL, 0) < 0))
88 		return -1;
89 
90 	return (paxflags & CTL_PROC_PAXFLAGS_MPROTECT) ? -1 : 0;
91 }
92 #endif /* PROT_MPROTECT */
93 #else /* POSIX */
94 #define check_se_protected(ptr, size) generic_se_protected(ptr, size)
95 
generic_se_protected(void * ptr,sljit_uw size)96 static SLJIT_INLINE int generic_se_protected(void *ptr, sljit_uw size)
97 {
98 	if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC)))
99 		return mprotect(ptr, size, PROT_READ | PROT_WRITE);
100 
101 	return -1;
102 }
103 #endif /* NetBSD */
104 
105 #if defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED
106 #define SLJIT_SE_LOCK()
107 #define SLJIT_SE_UNLOCK()
108 #else /* !SLJIT_SINGLE_THREADED */
109 #include <pthread.h>
110 #define SLJIT_SE_LOCK()	pthread_mutex_lock(&se_lock)
111 #define SLJIT_SE_UNLOCK()	pthread_mutex_unlock(&se_lock)
112 #endif /* SLJIT_SINGLE_THREADED */
113 
114 #ifndef SLJIT_PROT_WX
115 #define SLJIT_PROT_WX 0
116 #endif /* !SLJIT_PROT_WX */
117 
sljit_malloc_exec(sljit_uw size)118 SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
119 {
120 #if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
121 	static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
122 #endif
123 	static int se_protected = !SLJIT_PROT_WX;
124 	sljit_uw* ptr;
125 
126 	if (SLJIT_UNLIKELY(se_protected < 0))
127 		return NULL;
128 
129 	size += sizeof(sljit_uw);
130 	ptr = (sljit_uw*)mmap(NULL, size, PROT_READ | PROT_WRITE | SLJIT_PROT_WX,
131 				MAP_PRIVATE | MAP_ANON, -1, 0);
132 
133 	if (ptr == MAP_FAILED)
134 		return NULL;
135 
136 	if (SLJIT_UNLIKELY(se_protected > 0)) {
137 		SLJIT_SE_LOCK();
138 		se_protected = check_se_protected(ptr, size);
139 		SLJIT_SE_UNLOCK();
140 		if (SLJIT_UNLIKELY(se_protected < 0)) {
141 			munmap((void *)ptr, size);
142 			return NULL;
143 		}
144 	}
145 
146 	*ptr++ = size;
147 	return ptr;
148 }
149 
150 #undef SLJIT_PROT_WX
151 #undef SLJIT_SE_UNLOCK
152 #undef SLJIT_SE_LOCK
153 
sljit_free_exec(void * ptr)154 SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
155 {
156 	sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1;
157 	munmap((void*)start_ptr, *start_ptr);
158 }
159 
sljit_update_wx_flags(void * from,void * to,sljit_s32 enable_exec)160 static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
161 {
162 	sljit_uw page_mask = (sljit_uw)get_page_alignment();
163 	sljit_uw start = (sljit_uw)from;
164 	sljit_uw end = (sljit_uw)to;
165 	int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
166 
167 	SLJIT_ASSERT(start < end);
168 
169 	start &= ~page_mask;
170 	end = (end + page_mask) & ~page_mask;
171 
172 	mprotect((void*)start, end - start, prot);
173 }
174 
175 #else /* windows */
176 
sljit_malloc_exec(sljit_uw size)177 SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
178 {
179 	sljit_uw *ptr;
180 
181 	size += sizeof(sljit_uw);
182 	ptr = (sljit_uw*)VirtualAlloc(NULL, size,
183 				MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
184 
185 	if (!ptr)
186 		return NULL;
187 
188 	*ptr++ = size;
189 
190 	return ptr;
191 }
192 
sljit_free_exec(void * ptr)193 SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
194 {
195 	sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw);
196 #if defined(SLJIT_DEBUG) && SLJIT_DEBUG
197 	sljit_uw page_mask = (sljit_uw)get_page_alignment();
198 
199 	SLJIT_ASSERT(!(start & page_mask));
200 #endif
201 	VirtualFree((void*)start, 0, MEM_RELEASE);
202 }
203 
sljit_update_wx_flags(void * from,void * to,sljit_s32 enable_exec)204 static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
205 {
206 	DWORD oldprot;
207 	sljit_uw page_mask = (sljit_uw)get_page_alignment();
208 	sljit_uw start = (sljit_uw)from;
209 	sljit_uw end = (sljit_uw)to;
210 	DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE;
211 
212 	SLJIT_ASSERT(start < end);
213 
214 	start &= ~page_mask;
215 	end = (end + page_mask) & ~page_mask;
216 
217 	VirtualProtect((void*)start, end - start, prot, &oldprot);
218 }
219 
220 #endif /* !windows */
221 
sljit_free_unused_memory_exec(void)222 SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
223 {
224 	/* This allocator does not keep unused memory for future allocations. */
225 }
226