OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "debug.h" | |
6 #include "sandbox_impl.h" | |
7 | |
8 namespace playground { | |
9 | |
10 #ifndef IPC_PRIVATE | |
11 #define IPC_PRIVATE 0 | |
12 #endif | |
13 #ifndef IPC_RMID | |
14 #define IPC_RMID 0 | |
15 #endif | |
16 #ifndef IPC_64 | |
17 #define IPC_64 256 | |
18 #endif | |
19 | |
20 #if defined(__NR_shmget) | |
21 void* Sandbox::sandbox_shmat(int shmid, const void* shmaddr, int shmflg) { | |
22 long long tm; | |
23 Debug::syscall(&tm, __NR_shmat, "Executing handler"); | |
24 | |
25 struct { | |
26 int sysnum; | |
27 long long cookie; | |
28 ShmAt shmat_req; | |
29 } __attribute__((packed)) request; | |
30 request.sysnum = __NR_shmat; | |
31 request.cookie = cookie(); | |
32 request.shmat_req.shmid = shmid; | |
33 request.shmat_req.shmaddr = shmaddr; | |
34 request.shmat_req.shmflg = shmflg; | |
35 | |
36 long rc; | |
37 SysCalls sys; | |
38 if (write(sys, processFdPub(), &request, sizeof(request)) != | |
39 sizeof(request) || | |
40 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { | |
41 die("Failed to forward shmat() request [sandbox]"); | |
42 } | |
43 Debug::elapsed(tm, __NR_shmat); | |
44 return reinterpret_cast<void *>(rc); | |
45 } | |
46 | |
47 long Sandbox::sandbox_shmctl(int shmid, int cmd, void* buf) { | |
48 long long tm; | |
49 Debug::syscall(&tm, __NR_shmctl, "Executing handler"); | |
50 | |
51 struct { | |
52 int sysnum; | |
53 long long cookie; | |
54 ShmCtl shmctl_req; | |
55 } __attribute__((packed)) request; | |
56 request.sysnum = __NR_shmctl; | |
57 request.cookie = cookie(); | |
58 request.shmctl_req.shmid = shmid; | |
59 request.shmctl_req.cmd = cmd; | |
60 request.shmctl_req.buf = buf; | |
61 | |
62 long rc; | |
63 SysCalls sys; | |
64 if (write(sys, processFdPub(), &request, sizeof(request)) != | |
65 sizeof(request) || | |
66 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { | |
67 die("Failed to forward shmctl() request [sandbox]"); | |
68 } | |
69 Debug::elapsed(tm, __NR_shmctl); | |
70 return rc; | |
71 } | |
72 | |
73 long Sandbox::sandbox_shmdt(const void* shmaddr) { | |
74 long long tm; | |
75 Debug::syscall(&tm, __NR_shmdt, "Executing handler"); | |
76 | |
77 struct { | |
78 int sysnum; | |
79 long long cookie; | |
80 ShmDt shmdt_req; | |
81 } __attribute__((packed)) request; | |
82 request.sysnum = __NR_shmdt; | |
83 request.cookie = cookie(); | |
84 request.shmdt_req.shmaddr = shmaddr; | |
85 | |
86 long rc; | |
87 SysCalls sys; | |
88 if (write(sys, processFdPub(), &request, sizeof(request)) != | |
89 sizeof(request) || | |
90 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { | |
91 die("Failed to forward shmdt() request [sandbox]"); | |
92 } | |
93 Debug::elapsed(tm, __NR_shmdt); | |
94 return rc; | |
95 } | |
96 | |
97 long Sandbox::sandbox_shmget(int key, size_t size, int shmflg) { | |
98 long long tm; | |
99 Debug::syscall(&tm, __NR_shmget, "Executing handler"); | |
100 | |
101 struct { | |
102 int sysnum; | |
103 long long cookie; | |
104 ShmGet shmget_req; | |
105 } __attribute__((packed)) request; | |
106 request.sysnum = __NR_shmget; | |
107 request.cookie = cookie(); | |
108 request.shmget_req.key = key; | |
109 request.shmget_req.size = size; | |
110 request.shmget_req.shmflg = shmflg; | |
111 | |
112 long rc; | |
113 SysCalls sys; | |
114 if (write(sys, processFdPub(), &request, sizeof(request)) != | |
115 sizeof(request) || | |
116 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { | |
117 die("Failed to forward shmget() request [sandbox]"); | |
118 } | |
119 Debug::elapsed(tm, __NR_shmget); | |
120 return rc; | |
121 } | |
122 | |
123 bool Sandbox::process_shmat(int parentMapsFd, int sandboxFd, int threadFdPub, | |
124 int threadFd, SecureMem::Args* mem) { | |
125 // Read request | |
126 ShmAt shmat_req; | |
127 SysCalls sys; | |
128 if (read(sys, sandboxFd, &shmat_req, sizeof(shmat_req)) != | |
129 sizeof(shmat_req)) { | |
130 die("Failed to read parameters for shmat() [process]"); | |
131 } | |
132 | |
133 // We only allow attaching to the shm identifier that was returned by | |
134 // the most recent call to shmget(IPC_PRIVATE) | |
135 if (shmat_req.shmaddr || shmat_req.shmflg || shmat_req.shmid != mem->shmId) { | |
136 mem->shmId = -1; | |
137 SecureMem::abandonSystemCall(threadFd, -EINVAL); | |
138 return false; | |
139 } | |
140 | |
141 mem->shmId = -1; | |
142 SecureMem::sendSystemCall(threadFdPub, false, -1, mem, | |
143 __NR_shmat, shmat_req.shmid, shmat_req.shmaddr, | |
144 shmat_req.shmflg); | |
145 return true; | |
146 } | |
147 | |
148 bool Sandbox::process_shmctl(int parentMapsFd, int sandboxFd, int threadFdPub, | |
149 int threadFd, SecureMem::Args* mem) { | |
150 // Read request | |
151 ShmCtl shmctl_req; | |
152 SysCalls sys; | |
153 if (read(sys, sandboxFd, &shmctl_req, sizeof(shmctl_req)) != | |
154 sizeof(shmctl_req)) { | |
155 die("Failed to read parameters for shmctl() [process]"); | |
156 } | |
157 | |
158 // The only shmctl() operation that we need to support is removal. This | |
159 // operation is generally safe. | |
160 if ((shmctl_req.cmd & ~(IPC_64 | IPC_RMID)) || shmctl_req.buf) { | |
161 mem->shmId = -1; | |
162 SecureMem::abandonSystemCall(threadFd, -EINVAL); | |
163 return false; | |
164 } | |
165 | |
166 mem->shmId = -1; | |
167 SecureMem::sendSystemCall(threadFdPub, false, -1, mem, | |
168 __NR_shmctl, shmctl_req.shmid, shmctl_req.cmd, | |
169 shmctl_req.buf); | |
170 return true; | |
171 } | |
172 | |
173 bool Sandbox::process_shmdt(int parentMapsFd, int sandboxFd, int threadFdPub, | |
174 int threadFd, SecureMem::Args* mem) { | |
175 // Read request | |
176 ShmDt shmdt_req; | |
177 SysCalls sys; | |
178 if (read(sys, sandboxFd, &shmdt_req, sizeof(shmdt_req)) != | |
179 sizeof(shmdt_req)) { | |
180 die("Failed to read parameters for shmdt() [process]"); | |
181 } | |
182 | |
183 // Detaching shared memory segments it generally safe, but just in case | |
184 // of a kernel bug, we make sure that the address does not fall into any | |
185 // of the reserved memory regions. | |
186 ProtectedMap::const_iterator iter = protectedMap_.lower_bound( | |
187 (void *)shmdt_req.shmaddr); | |
188 if (iter != protectedMap_.begin()) { | |
189 --iter; | |
190 } | |
191 for (; iter != protectedMap_.end() && iter->first <= shmdt_req.shmaddr; | |
192 ++iter){ | |
193 if (shmdt_req.shmaddr < reinterpret_cast<void *>( | |
194 reinterpret_cast<char *>(iter->first) + iter->second) && | |
195 shmdt_req.shmaddr >= iter->first) { | |
196 mem->shmId = -1; | |
197 SecureMem::abandonSystemCall(threadFd, -EINVAL); | |
198 return false; | |
199 } | |
200 } | |
201 | |
202 mem->shmId = -1; | |
203 SecureMem::sendSystemCall(threadFdPub, false, -1, mem, | |
204 __NR_shmdt, shmdt_req.shmaddr); | |
205 return true; | |
206 } | |
207 | |
208 bool Sandbox::process_shmget(int parentMapsFd, int sandboxFd, int threadFdPub, | |
209 int threadFd, SecureMem::Args* mem) { | |
210 // Read request | |
211 ShmGet shmget_req; | |
212 SysCalls sys; | |
213 if (read(sys, sandboxFd, &shmget_req, sizeof(shmget_req)) != | |
214 sizeof(shmget_req)) { | |
215 die("Failed to read parameters for shmget() [process]"); | |
216 } | |
217 | |
218 // We do not want to allow the sandboxed application to access arbitrary | |
219 // shared memory regions. We only allow it to access regions that it | |
220 // created itself. | |
221 if (shmget_req.key != IPC_PRIVATE || shmget_req.shmflg & ~0777) { | |
222 mem->shmId = -1; | |
223 SecureMem::abandonSystemCall(threadFd, -EINVAL); | |
224 return false; | |
225 } | |
226 | |
227 mem->shmId = -1; | |
228 SecureMem::sendSystemCall(threadFdPub, false, -1, mem, | |
229 __NR_shmget, shmget_req.key, shmget_req.size, | |
230 shmget_req.shmflg); | |
231 return true; | |
232 } | |
233 #endif | |
234 | |
235 #if defined(__NR_ipc) | |
236 #ifndef SHMAT | |
237 #define SHMAT 21 | |
238 #endif | |
239 #ifndef SHMDT | |
240 #define SHMDT 22 | |
241 #endif | |
242 #ifndef SHMGET | |
243 #define SHMGET 23 | |
244 #endif | |
245 #ifndef SHMCTL | |
246 #define SHMCTL 24 | |
247 #endif | |
248 | |
249 long Sandbox::sandbox_ipc(unsigned call, int first, int second, int third, | |
250 void* ptr, long fifth) { | |
251 long long tm; | |
252 Debug::syscall(&tm, __NR_ipc, "Executing handler", call); | |
253 struct { | |
254 int sysnum; | |
255 long long cookie; | |
256 IPC ipc_req; | |
257 } __attribute__((packed)) request; | |
258 request.sysnum = __NR_ipc; | |
259 request.cookie = cookie(); | |
260 request.ipc_req.call = call; | |
261 request.ipc_req.first = first; | |
262 request.ipc_req.second = second; | |
263 request.ipc_req.third = third; | |
264 request.ipc_req.ptr = ptr; | |
265 request.ipc_req.fifth = fifth; | |
266 | |
267 long rc; | |
268 SysCalls sys; | |
269 if (write(sys, processFdPub(), &request, sizeof(request)) != | |
270 sizeof(request) || | |
271 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { | |
272 die("Failed to forward ipc() request [sandbox]"); | |
273 } | |
274 Debug::elapsed(tm, __NR_ipc, call); | |
275 return rc; | |
276 } | |
277 | |
278 bool Sandbox::process_ipc(int parentMapsFd, int sandboxFd, int threadFdPub, | |
279 int threadFd, SecureMem::Args* mem) { | |
280 // Read request | |
281 IPC ipc_req; | |
282 SysCalls sys; | |
283 if (read(sys, sandboxFd, &ipc_req, sizeof(ipc_req)) != sizeof(ipc_req)) { | |
284 die("Failed to read parameters for ipc() [process]"); | |
285 } | |
286 | |
287 // We do not support all of the SysV IPC calls. In fact, we only support | |
288 // the minimum feature set necessary for Chrome's renderers to share memory | |
289 // with the X server. | |
290 switch (ipc_req.call) { | |
291 case SHMAT: { | |
292 // We only allow attaching to the shm identifier that was returned by | |
293 // the most recent call to shmget(IPC_PRIVATE) | |
294 if (ipc_req.ptr || ipc_req.second || ipc_req.first != mem->shmId) { | |
295 goto deny; | |
296 } | |
297 accept: | |
298 mem->shmId = -1; | |
299 SecureMem::sendSystemCall(threadFdPub, false, -1, mem, | |
300 __NR_ipc, ipc_req.call, ipc_req.first, | |
301 ipc_req.second, ipc_req.third, ipc_req.ptr, | |
302 ipc_req.fifth); | |
303 return true; | |
304 } | |
305 case SHMCTL: | |
306 // The only shmctl() operation that we need to support is removal. This | |
307 // operation is generally safe. | |
308 if ((ipc_req.second & ~(IPC_64 | IPC_RMID)) || ipc_req.ptr) { | |
309 goto deny; | |
310 } else { | |
311 goto accept; | |
312 } | |
313 case SHMDT: { | |
314 // Detaching shared memory segments it generally safe, but just in case | |
315 // of a kernel bug, we make sure that the address does not fall into any | |
316 // of the reserved memory regions. | |
317 ProtectedMap::const_iterator iter = protectedMap_.lower_bound( | |
318 (void *)ipc_req.ptr); | |
319 if (iter != protectedMap_.begin()) { | |
320 --iter; | |
321 } | |
322 for (; iter != protectedMap_.end() && iter->first <=ipc_req.ptr; ++iter){ | |
323 if (ipc_req.ptr < reinterpret_cast<void *>( | |
324 reinterpret_cast<char *>(iter->first) + iter->second) && | |
325 ipc_req.ptr >= iter->first) { | |
326 goto deny; | |
327 } | |
328 } | |
329 goto accept; | |
330 } | |
331 case SHMGET: | |
332 // We do not want to allow the sandboxed application to access arbitrary | |
333 // shared memory regions. We only allow it to access regions that it | |
334 // created itself. | |
335 if (ipc_req.first != IPC_PRIVATE || ipc_req.third & ~0777) { | |
336 goto deny; | |
337 } else { | |
338 goto accept; | |
339 } | |
340 default: | |
341 // Other than SysV shared memory, we do not actually need to support any | |
342 // other SysV IPC calls. | |
343 deny: | |
344 mem->shmId = -1; | |
345 SecureMem::abandonSystemCall(threadFd, -EINVAL); | |
346 return false; | |
347 } | |
348 } | |
349 #endif | |
350 | |
351 } // namespace | |
OLD | NEW |