1 /****************************************************************************
2 **
3 ** Copyright (C) Rolland Dudemaine All rights reserved.
4 ** Copyright (C) 2016 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtQml module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "config.h"
42 #include "OSAllocator.h"
43 
44 #include <INTEGRITY.h>
45 #include <memory_region.h>
46 #include <set>
47 #include <wtf/Assertions.h>
48 #include <wtf/UnusedParam.h>
49 
50 #define ASP_PAGESIZE    0x1000
51 
52 namespace WTF {
53 struct MRPair {
54     mutable MemoryRegion    pmr;
55     mutable MemoryRegion    vmr;
56 
57     mutable bool mapped;
58 
59     Address start;
60 
MRPairWTF::MRPair61     MRPair(Address _start = 0) :
62         pmr(0),
63         vmr(0),
64         mapped(false),
65         start(_start)
66     {}
67 
operator <WTF::MRPair68     bool operator<(const MRPair& rhs) const
69     {
70         return this->start < rhs.start;
71     }
72 };
73 
74 class MRContainer
75 {
76 private:
77     std::set<MRPair>        mrset;
78     LocalMutex              iteratorGuard;
79 public:
MRContainer()80     MRContainer() {
81         CheckSuccess(CreateLocalMutex(&iteratorGuard));
82     }
getMRPair(Address start)83     const MRPair* getMRPair(Address start) {
84         WaitForLocalMutex(iteratorGuard);
85         auto pairIterator = mrset.find(MRPair(start));
86         const MRPair* result = ((pairIterator == mrset.end()) ? NULL : &(*pairIterator));
87         ReleaseLocalMutex(iteratorGuard);
88         return result;
89     }
deleteMRPair(const MRPair * pair)90     Error deleteMRPair(const MRPair* pair) {
91         int erased = 0;
92         WaitForLocalMutex(iteratorGuard);
93         erased = mrset.erase(*pair);
94         ReleaseLocalMutex(iteratorGuard);
95         if(erased == 1)
96             return Success;
97         else
98             return ArgumentError;   /* An exception could be thrown in this case */
99     }
insertMRPair(MRPair * pair)100     Error insertMRPair(MRPair* pair) {
101         WaitForLocalMutex(iteratorGuard);
102         auto inserted = mrset.insert(*pair);
103         ReleaseLocalMutex(iteratorGuard);
104         if(inserted.second == true)
105             return Success;
106         else
107             return Failure;         /* An exception could be thrown in this case */
108     }
~MRContainer()109     ~MRContainer() {
110         CheckSuccess(CloseLocalMutex(iteratorGuard));
111     }
112 };
113 
114 static MRContainer memoryRegionsContainer;
115 
setAttributes(MemoryRegion mr,bool writable,bool executable)116 Error setAttributes(MemoryRegion mr, bool writable, bool executable)
117 {
118     Value attributes = MEMORY_READ;
119     if(writable)
120         attributes |= MEMORY_WRITE;
121     if(executable)
122         attributes |= MEMORY_EXEC;
123     return SetMemoryRegionAttributes(mr, attributes);
124 }
125 
setMemoryAttributes(void * addr,size_t size,bool writable,bool executable)126 void OSAllocator::setMemoryAttributes(void* addr, size_t size, bool writable, bool executable)
127 {
128     Address addressIterator = Address(addr);
129     for(int i=0; i<(size + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
130         const MRPair* pair = memoryRegionsContainer.getMRPair(addressIterator);
131         CheckSuccess(setAttributes(pair->vmr, writable, executable));
132         addressIterator += ASP_PAGESIZE;
133     }
134 }
135 
reserveUncommitted(size_t bytes,Usage usage,bool writable,bool executable)136 void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
137 {
138     MemoryRegion VMR;
139 
140     Address virtualStart, length;
141 
142     CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
143     CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
144     Address addressIterator = virtualStart;
145     for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
146         MRPair pair;
147         pair.start = addressIterator;
148         CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
149         CheckSuccess(setAttributes(pair.vmr, writable, executable));
150 
151         memoryRegionsContainer.insertMRPair(&pair);
152         addressIterator += ASP_PAGESIZE;
153     }
154 
155     CheckSuccess(CloseMemoryRegion(VMR));
156     return (void*)virtualStart;
157 }
158 
reserveAndCommit(size_t bytes,Usage usage,bool writable,bool executable,bool includesGuardPages)159 void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
160 {
161     MemoryRegion VMR;
162 
163     Address virtualStart, length;
164 
165     CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
166     CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
167 
168     Address addressIterator = virtualStart;
169     for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
170         MRPair pair;
171         pair.start = addressIterator;
172         CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
173         CheckSuccess(setAttributes(pair.vmr, writable, executable));
174         /* Do not map the first and the last pages if guard pages are required */
175         if(!includesGuardPages || (i!=0 && i!= (bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE -1))
176         {
177             CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair.pmr));
178             CheckSuccess(MapMemoryRegion(pair.vmr, pair.pmr));
179             pair.mapped = true;
180         }
181 
182         memoryRegionsContainer.insertMRPair(&pair);
183         addressIterator += ASP_PAGESIZE;
184     }
185 
186     CheckSuccess(CloseMemoryRegion(VMR));
187     return (void*)virtualStart;
188 }
189 
commit(void * address,size_t bytes,bool writable,bool executable)190 void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
191 {
192     for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
193     {
194         const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
195         if(pair == NULL)
196             return;
197         CheckSuccess(setAttributes(pair->vmr, writable, executable));
198         CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair->pmr));
199         CheckSuccess(MapMemoryRegion(pair->vmr, pair->pmr));
200         pair->mapped = true;
201         address = (char*)address +  ASP_PAGESIZE;
202     }
203 }
204 
decommit(void * address,size_t bytes)205 void OSAllocator::decommit(void* address, size_t bytes)
206 {
207     for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
208     {
209         const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
210         if(pair == NULL)
211             return;
212         if(pair->mapped == false)
213             continue;
214 
215         CheckSuccess(UnmapMemoryRegion(pair->vmr));
216         CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
217         pair->mapped = false;
218         address = (char*)address + ASP_PAGESIZE;
219     }
220 }
221 
releaseDecommitted(void * address,size_t bytes)222 void OSAllocator::releaseDecommitted(void* address, size_t bytes)
223 {
224     for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
225     {
226         const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
227         if(pair == NULL)
228             return;
229         /* Check if the memory is still committed */
230         if(pair->mapped == true)
231         {
232             CheckSuccess(UnmapMemoryRegion(pair->vmr));
233             CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
234             pair->mapped = false;
235         }
236         CheckSuccess(AddToMemoryPool(__ghs_VirtualMemoryRegionPool, pair->vmr));
237         address = (char*)address + ASP_PAGESIZE;
238 
239         memoryRegionsContainer.deleteMRPair(pair);
240     }
241 }
242 
canAllocateExecutableMemory()243 bool OSAllocator::canAllocateExecutableMemory()
244 {
245     return true;
246 }
247 
248 } // namespace WTF
249