| 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 |