Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: sandbox/linux/seccomp/socketcall.cc

Issue 3225010: Pull seccomp-sandbox in via DEPS rather than using an in-tree copy... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/linux/seccomp/sigprocmask.cc ('k') | sandbox/linux/seccomp/stat.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 #if defined(__NR_socket)
11
12 ssize_t Sandbox::sandbox_recvfrom(int sockfd, void* buf, size_t len, int flags,
13 void* from, socklen_t* fromlen) {
14 long long tm;
15 Debug::syscall(&tm, __NR_recvfrom, "Executing handler");
16
17 SysCalls sys;
18 if (!from && !flags) {
19 // recv() with a NULL sender and no flags is the same as read(), which
20 // is unrestricted in seccomp mode.
21 Debug::message("Replaced recv() with call to read()");
22 ssize_t rc = sys.read(sockfd, buf, len);
23 if (rc < 0) {
24 Debug::elapsed(tm, __NR_recvfrom);
25 return -sys.my_errno;
26 } else {
27 Debug::elapsed(tm, __NR_recvfrom);
28 return rc;
29 }
30 }
31
32 struct {
33 int sysnum;
34 long long cookie;
35 RecvFrom recvfrom_req;
36 } __attribute__((packed)) request;
37 request.sysnum = __NR_recvfrom;
38 request.cookie = cookie();
39 request.recvfrom_req.sockfd = sockfd;
40 request.recvfrom_req.buf = buf;
41 request.recvfrom_req.len = len;
42 request.recvfrom_req.flags = flags;
43 request.recvfrom_req.from = from;
44 request.recvfrom_req.fromlen = fromlen;
45
46 long rc;
47 if (write(sys, processFdPub(), &request, sizeof(request)) !=
48 sizeof(request) ||
49 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
50 die("Failed to forward recvfrom() request [sandbox]");
51 }
52 Debug::elapsed(tm, __NR_recvfrom);
53 return static_cast<ssize_t>(rc);
54 }
55
56 ssize_t Sandbox::sandbox_recvmsg(int sockfd, struct msghdr* msg, int flags) {
57 long long tm;
58 Debug::syscall(&tm, __NR_recvmsg, "Executing handler");
59
60 // We cannot simplify recvmsg() to recvfrom(), recv() or read(), as we do
61 // not know whether the caller needs us to set msg->msg_flags.
62 struct {
63 int sysnum;
64 long long cookie;
65 RecvMsg recvmsg_req;
66 } __attribute__((packed)) request;
67 request.sysnum = __NR_recvmsg;
68 request.cookie = cookie();
69 request.recvmsg_req.sockfd = sockfd;
70 request.recvmsg_req.msg = msg;
71 request.recvmsg_req.flags = flags;
72
73 long rc;
74 SysCalls sys;
75 if (write(sys, processFdPub(), &request, sizeof(request)) !=
76 sizeof(request) ||
77 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
78 die("Failed to forward recvmsg() request [sandbox]");
79 }
80 Debug::elapsed(tm, __NR_recvmsg);
81 return static_cast<ssize_t>(rc);
82 }
83
84 size_t Sandbox::sandbox_sendmsg(int sockfd, const struct msghdr* msg,
85 int flags) {
86 long long tm;
87 Debug::syscall(&tm, __NR_sendmsg, "Executing handler");
88
89 if (msg->msg_iovlen == 1 && msg->msg_controllen == 0) {
90 // sendmsg() can sometimes be simplified as sendto()
91 return sandbox_sendto(sockfd, msg->msg_iov, msg->msg_iovlen,
92 flags, msg->msg_name, msg->msg_namelen);
93 }
94
95 struct Request {
96 int sysnum;
97 long long cookie;
98 SendMsg sendmsg_req;
99 struct msghdr msg;
100 } __attribute__((packed));
101 char data[sizeof(struct Request) + msg->msg_namelen + msg->msg_controllen];
102 struct Request *request = reinterpret_cast<struct Request *>(data);
103 request->sysnum = __NR_sendmsg;
104 request->cookie = cookie();
105 request->sendmsg_req.sockfd = sockfd;
106 request->sendmsg_req.msg = msg;
107 request->sendmsg_req.flags = flags;
108 request->msg = *msg;
109 memcpy(reinterpret_cast<char *>(
110 memcpy(request + 1, msg->msg_name, msg->msg_namelen)) +
111 msg->msg_namelen,
112 msg->msg_control, msg->msg_controllen);
113
114 long rc;
115 SysCalls sys;
116 if (write(sys, processFdPub(), &data, sizeof(data)) !=
117 (ssize_t)sizeof(data) ||
118 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
119 die("Failed to forward sendmsg() request [sandbox]");
120 }
121 Debug::elapsed(tm, __NR_sendmsg);
122 return static_cast<ssize_t>(rc);
123 }
124
125 ssize_t Sandbox::sandbox_sendto(int sockfd, const void* buf, size_t len,
126 int flags, const void* to, socklen_t tolen) {
127 long long tm;
128 Debug::syscall(&tm, __NR_sendto, "Executing handler");
129
130 SysCalls sys;
131 if (!to && !flags) {
132 // sendto() with a NULL recipient and no flags is the same as write(),
133 // which is unrestricted in seccomp mode.
134 Debug::message("Replaced sendto() with call to write()");
135 ssize_t rc = sys.write(sockfd, buf, len);
136 if (rc < 0) {
137 Debug::elapsed(tm, __NR_sendto);
138 return -sys.my_errno;
139 } else {
140 Debug::elapsed(tm, __NR_sendto);
141 return rc;
142 }
143 }
144
145 struct {
146 int sysnum;
147 long long cookie;
148 SendTo sendto_req;
149 } __attribute__((packed)) request;
150 request.sysnum = __NR_sendto;
151 request.cookie = cookie();
152 request.sendto_req.sockfd = sockfd;
153 request.sendto_req.buf = buf;
154 request.sendto_req.len = len;
155 request.sendto_req.flags = flags;
156 request.sendto_req.to = to;
157 request.sendto_req.tolen = tolen;
158
159 long rc;
160 if (write(sys, processFdPub(), &request, sizeof(request)) !=
161 sizeof(request) ||
162 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
163 die("Failed to forward sendto() request [sandbox]");
164 }
165 Debug::elapsed(tm, __NR_sendto);
166 return static_cast<ssize_t>(rc);
167 }
168
169 long Sandbox::sandbox_setsockopt(int sockfd, int level, int optname,
170 const void* optval, socklen_t optlen) {
171 long long tm;
172 Debug::syscall(&tm, __NR_setsockopt, "Executing handler");
173
174 struct {
175 int sysnum;
176 long long cookie;
177 SetSockOpt setsockopt_req;
178 } __attribute__((packed)) request;
179 request.sysnum = __NR_setsockopt;
180 request.cookie = cookie();
181 request.setsockopt_req.sockfd = sockfd;
182 request.setsockopt_req.level = level;
183 request.setsockopt_req.optname = optname;
184 request.setsockopt_req.optval = optval;
185 request.setsockopt_req.optlen = optlen;
186
187 long rc;
188 SysCalls sys;
189 if (write(sys, processFdPub(), &request, sizeof(request)) !=
190 sizeof(request) ||
191 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
192 die("Failed to forward setsockopt() request [sandbox]");
193 }
194 Debug::elapsed(tm, __NR_setsockopt);
195 return rc;
196 }
197
198 long Sandbox::sandbox_getsockopt(int sockfd, int level, int optname,
199 void* optval, socklen_t* optlen) {
200 long long tm;
201 Debug::syscall(&tm, __NR_getsockopt, "Executing handler");
202
203 struct {
204 int sysnum;
205 long long cookie;
206 GetSockOpt getsockopt_req;
207 } __attribute__((packed)) request;
208 request.sysnum = __NR_getsockopt;
209 request.cookie = cookie();
210 request.getsockopt_req.sockfd = sockfd;
211 request.getsockopt_req.level = level;
212 request.getsockopt_req.optname = optname;
213 request.getsockopt_req.optval = optval;
214 request.getsockopt_req.optlen = optlen;
215
216 long rc;
217 SysCalls sys;
218 if (write(sys, processFdPub(), &request, sizeof(request)) !=
219 sizeof(request) ||
220 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
221 die("Failed to forward getsockopt() request [sandbox]");
222 }
223 Debug::elapsed(tm, __NR_getsockopt);
224 return rc;
225 }
226
227 bool Sandbox::process_recvfrom(int parentMapsFd, int sandboxFd,
228 int threadFdPub, int threadFd,
229 SecureMem::Args* mem) {
230 // Read request
231 RecvFrom recvfrom_req;
232 SysCalls sys;
233 if (read(sys, sandboxFd, &recvfrom_req, sizeof(recvfrom_req)) !=
234 sizeof(recvfrom_req)) {
235 die("Failed to read parameters for recvfrom() [process]");
236 }
237
238 // Unsupported flag encountered. Deny the call.
239 if (recvfrom_req.flags &
240 ~(MSG_DONTWAIT|MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_WAITALL)) {
241 SecureMem::abandonSystemCall(threadFd, -EINVAL);
242 return false;
243 }
244
245 // While we do not anticipate any particular need to receive data on
246 // unconnected sockets, there is no particular risk in doing so.
247 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
248 __NR_recvfrom, recvfrom_req.sockfd,
249 recvfrom_req.buf, recvfrom_req.len,
250 recvfrom_req.flags, recvfrom_req.from,
251 recvfrom_req.fromlen);
252 return true;
253 }
254
255 bool Sandbox::process_recvmsg(int parentMapsFd, int sandboxFd, int threadFdPub,
256 int threadFd, SecureMem::Args* mem) {
257 // Read request
258 RecvMsg recvmsg_req;
259 SysCalls sys;
260 if (read(sys, sandboxFd, &recvmsg_req, sizeof(recvmsg_req)) !=
261 sizeof(recvmsg_req)) {
262 die("Failed to read parameters for recvmsg() [process]");
263 }
264
265 // Unsupported flag encountered. Deny the call.
266 if (recvmsg_req.flags &
267 ~(MSG_DONTWAIT|MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_WAITALL)) {
268 SecureMem::abandonSystemCall(threadFd, -EINVAL);
269 return false;
270 }
271
272 // Receiving messages is general not security critical.
273 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
274 __NR_recvmsg, recvmsg_req.sockfd,
275 recvmsg_req.msg, recvmsg_req.flags);
276 return true;
277 }
278
279 bool Sandbox::process_sendmsg(int parentMapsFd, int sandboxFd, int threadFdPub,
280 int threadFd, SecureMem::Args* mem) {
281 // Read request
282 struct {
283 SendMsg sendmsg_req;
284 struct msghdr msg;
285 } __attribute__((packed)) data;
286 SysCalls sys;
287 if (read(sys, sandboxFd, &data, sizeof(data)) != sizeof(data)) {
288 die("Failed to read parameters for sendmsg() [process]");
289 }
290
291 if (data.msg.msg_namelen > 4096 || data.msg.msg_controllen > 4096) {
292 die("Unexpected size for socketcall() payload [process]");
293 }
294 char extra[data.msg.msg_namelen + data.msg.msg_controllen];
295 if (read(sys, sandboxFd, &extra, sizeof(extra)) != (ssize_t)sizeof(extra)) {
296 die("Failed to read parameters for sendmsg() [process]");
297 }
298 if (sizeof(struct msghdr) + sizeof(extra) > sizeof(mem->pathname)) {
299 goto deny;
300 }
301
302 if (data.msg.msg_namelen ||
303 (data.sendmsg_req.flags &
304 ~(MSG_CONFIRM|MSG_DONTWAIT|MSG_EOR|MSG_MORE|MSG_NOSIGNAL|MSG_OOB))) {
305 deny:
306 SecureMem::abandonSystemCall(threadFd, -EINVAL);
307 return false;
308 }
309
310 // The trusted process receives file handles when a new untrusted thread
311 // gets created. We have security checks in place that prevent any
312 // critical information from being tampered with during thread creation.
313 // But if we disallowed passing of file handles, this would add an extra
314 // hurdle for an attacker.
315 // Unfortunately, for now, this is not possible as Chrome's
316 // base::SendRecvMsg() needs the ability to pass file handles.
317 if (data.msg.msg_controllen) {
318 data.msg.msg_control = extra + data.msg.msg_namelen;
319 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&data.msg);
320 do {
321 if (cmsg->cmsg_level != SOL_SOCKET ||
322 cmsg->cmsg_type != SCM_RIGHTS) {
323 goto deny;
324 }
325 } while ((cmsg = CMSG_NXTHDR(&data.msg, cmsg)) != NULL);
326 }
327
328 // This must be a locked system call, because we have to ensure that the
329 // untrusted code does not tamper with the msghdr after we have examined it.
330 SecureMem::lockSystemCall(parentMapsFd, mem);
331 if (sizeof(extra) > 0) {
332 if (data.msg.msg_namelen > 0) {
333 data.msg.msg_name = mem->pathname + sizeof(struct msghdr);
334 }
335 if (data.msg.msg_controllen > 0) {
336 data.msg.msg_control = mem->pathname + sizeof(struct msghdr) +
337 data.msg.msg_namelen;
338 }
339 memcpy(mem->pathname + sizeof(struct msghdr), extra, sizeof(extra));
340 }
341 memcpy(mem->pathname, &data.msg, sizeof(struct msghdr));
342 SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem,
343 __NR_sendmsg, data.sendmsg_req.sockfd,
344 mem->pathname - (char*)mem + (char*)mem->self,
345 data.sendmsg_req.flags);
346 return true;
347 }
348
349 bool Sandbox::process_sendto(int parentMapsFd, int sandboxFd, int threadFdPub,
350 int threadFd, SecureMem::Args* mem) {
351 // Read request
352 SendTo sendto_req;
353 SysCalls sys;
354 if (read(sys, sandboxFd, &sendto_req, sizeof(sendto_req)) !=
355 sizeof(sendto_req)) {
356 die("Failed to read parameters for sendto() [process]");
357 }
358
359 // The sandbox does not allow sending to arbitrary addresses.
360 if (sendto_req.to) {
361 SecureMem::abandonSystemCall(threadFd, -EINVAL);
362 return false;
363 }
364
365 // Unsupported flag encountered. Deny the call.
366 if (sendto_req.flags &
367 ~(MSG_CONFIRM|MSG_DONTWAIT|MSG_EOR|MSG_MORE|MSG_NOSIGNAL|MSG_OOB)) {
368 SecureMem::abandonSystemCall(threadFd, -EINVAL);
369 return false;
370 }
371
372 // Sending data on a connected socket is similar to calling write().
373 // Allow it.
374 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
375 __NR_sendto, sendto_req.sockfd,
376 sendto_req.buf, sendto_req.len,
377 sendto_req.flags, sendto_req.to,
378 sendto_req.tolen);
379 return true;
380 }
381
382 bool Sandbox::process_setsockopt(int parentMapsFd, int sandboxFd,
383 int threadFdPub, int threadFd,
384 SecureMem::Args* mem) {
385 // Read request
386 SetSockOpt setsockopt_req;
387 SysCalls sys;
388 if (read(sys, sandboxFd, &setsockopt_req, sizeof(setsockopt_req)) !=
389 sizeof(setsockopt_req)) {
390 die("Failed to read parameters for setsockopt() [process]");
391 }
392
393 switch (setsockopt_req.level) {
394 case SOL_SOCKET:
395 switch (setsockopt_req.optname) {
396 case SO_KEEPALIVE:
397 case SO_LINGER:
398 case SO_OOBINLINE:
399 case SO_RCVBUF:
400 case SO_RCVLOWAT:
401 case SO_SNDLOWAT:
402 case SO_RCVTIMEO:
403 case SO_SNDTIMEO:
404 case SO_REUSEADDR:
405 case SO_SNDBUF:
406 case SO_TIMESTAMP:
407 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
408 __NR_setsockopt, setsockopt_req.sockfd,
409 setsockopt_req.level, setsockopt_req.optname,
410 setsockopt_req.optval, setsockopt_req.optlen);
411 return true;
412 default:
413 break;
414 }
415 break;
416 case IPPROTO_TCP:
417 switch (setsockopt_req.optname) {
418 case TCP_CORK:
419 case TCP_DEFER_ACCEPT:
420 case TCP_INFO:
421 case TCP_KEEPCNT:
422 case TCP_KEEPIDLE:
423 case TCP_KEEPINTVL:
424 case TCP_LINGER2:
425 case TCP_MAXSEG:
426 case TCP_NODELAY:
427 case TCP_QUICKACK:
428 case TCP_SYNCNT:
429 case TCP_WINDOW_CLAMP:
430 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
431 __NR_setsockopt, setsockopt_req.sockfd,
432 setsockopt_req.level, setsockopt_req.optname,
433 setsockopt_req.optval, setsockopt_req.optlen);
434 return true;
435 default:
436 break;
437 }
438 break;
439 default:
440 break;
441 }
442 SecureMem::abandonSystemCall(threadFd, -EINVAL);
443 return false;
444 }
445
446 bool Sandbox::process_getsockopt(int parentMapsFd, int sandboxFd,
447 int threadFdPub, int threadFd,
448 SecureMem::Args* mem) {
449 // Read request
450 GetSockOpt getsockopt_req;
451 SysCalls sys;
452 if (read(sys, sandboxFd, &getsockopt_req, sizeof(getsockopt_req)) !=
453 sizeof(getsockopt_req)) {
454 die("Failed to read parameters for getsockopt() [process]");
455 }
456
457 switch (getsockopt_req.level) {
458 case SOL_SOCKET:
459 switch (getsockopt_req.optname) {
460 case SO_ACCEPTCONN:
461 case SO_ERROR:
462 case SO_KEEPALIVE:
463 case SO_LINGER:
464 case SO_OOBINLINE:
465 case SO_RCVBUF:
466 case SO_RCVLOWAT:
467 case SO_SNDLOWAT:
468 case SO_RCVTIMEO:
469 case SO_SNDTIMEO:
470 case SO_REUSEADDR:
471 case SO_SNDBUF:
472 case SO_TIMESTAMP:
473 case SO_TYPE:
474 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
475 __NR_getsockopt, getsockopt_req.sockfd,
476 getsockopt_req.level, getsockopt_req.optname,
477 getsockopt_req.optval, getsockopt_req.optlen);
478 return true;
479 default:
480 break;
481 }
482 break;
483 case IPPROTO_TCP:
484 switch (getsockopt_req.optname) {
485 case TCP_CORK:
486 case TCP_DEFER_ACCEPT:
487 case TCP_INFO:
488 case TCP_KEEPCNT:
489 case TCP_KEEPIDLE:
490 case TCP_KEEPINTVL:
491 case TCP_LINGER2:
492 case TCP_MAXSEG:
493 case TCP_NODELAY:
494 case TCP_QUICKACK:
495 case TCP_SYNCNT:
496 case TCP_WINDOW_CLAMP:
497 SecureMem::sendSystemCall(threadFdPub, false, -1, mem,
498 __NR_getsockopt, getsockopt_req.sockfd,
499 getsockopt_req.level, getsockopt_req.optname,
500 getsockopt_req.optval, getsockopt_req.optlen);
501 return true;
502 default:
503 break;
504 }
505 break;
506 default:
507 break;
508 }
509 SecureMem::abandonSystemCall(threadFd, -EINVAL);
510 return false;
511 }
512
513 #endif
514 #if defined(__NR_socketcall)
515
516 enum {
517 SYS_SOCKET = 1,
518 SYS_BIND = 2,
519 SYS_CONNECT = 3,
520 SYS_LISTEN = 4,
521 SYS_ACCEPT = 5,
522 SYS_GETSOCKNAME = 6,
523 SYS_GETPEERNAME = 7,
524 SYS_SOCKETPAIR = 8,
525 SYS_SEND = 9,
526 SYS_RECV = 10,
527 SYS_SENDTO = 11,
528 SYS_RECVFROM = 12,
529 SYS_SHUTDOWN = 13,
530 SYS_SETSOCKOPT = 14,
531 SYS_GETSOCKOPT = 15,
532 SYS_SENDMSG = 16,
533 SYS_RECVMSG = 17,
534 SYS_ACCEPT4 = 18
535 };
536
537 struct Sandbox::SocketCallArgInfo {
538 size_t len;
539 off_t addrOff;
540 off_t lengthOff;
541 };
542 const struct Sandbox::SocketCallArgInfo Sandbox::socketCallArgInfo[] = {
543 #define STRUCT(s) reinterpret_cast<SocketCall *>(0)->args.s
544 #define SIZE(s) sizeof(STRUCT(s))
545 #define OFF(s, f) offsetof(typeof STRUCT(s), f)
546 { 0 },
547 { SIZE(socket) },
548 { SIZE(bind), OFF(bind, addr), OFF(bind, addrlen) },
549 { SIZE(connect), OFF(connect, addr), OFF(connect, addrlen) },
550 { SIZE(listen) },
551 { SIZE(accept) },
552 { SIZE(getsockname) },
553 { SIZE(getpeername) },
554 { SIZE(socketpair) },
555 { SIZE(send) },
556 { SIZE(recv) },
557 { SIZE(sendto), OFF(sendto, to), OFF(sendto, tolen) },
558 { SIZE(recvfrom) },
559 { SIZE(shutdown) },
560 { SIZE(setsockopt), OFF(setsockopt, optval), OFF(setsockopt, optlen) },
561 { SIZE(getsockopt) },
562 { SIZE(sendmsg) },
563 { SIZE(recvmsg) },
564 { SIZE(accept4) }
565 #undef STRUCT
566 #undef SIZE
567 #undef OFF
568 };
569
570 long Sandbox::sandbox_socketcall(int call, void* args) {
571 long long tm;
572 Debug::syscall(&tm, __NR_socketcall, "Executing handler", call);
573
574 // When demultiplexing socketcall(), only accept calls that have a valid
575 // "call" opcode.
576 if (call < SYS_SOCKET || call > SYS_ACCEPT4) {
577 Debug::elapsed(tm, __NR_socketcall, call);
578 return -ENOSYS;
579 }
580
581 // Some type of calls include a pointer to an address or name, which cannot
582 // be accessed by the trusted process, as it lives in a separate address
583 // space. For these calls, append the extra data to the serialized request.
584 // This requires some copying of data, as we have to make sure there is
585 // only a single atomic call to write().
586 socklen_t numExtraData = 0;
587 const void* extraDataAddr = NULL;
588 if (socketCallArgInfo[call].lengthOff) {
589 memcpy(&numExtraData,
590 reinterpret_cast<char *>(args) + socketCallArgInfo[call].lengthOff,
591 sizeof(socklen_t));
592 extraDataAddr = reinterpret_cast<char *>(args) +
593 socketCallArgInfo[call].addrOff;
594 }
595
596 // sendmsg() and recvmsg() have more complicated requirements for computing
597 // the amount of extra data that needs to be sent to the trusted process.
598 if (call == SYS_SENDMSG) {
599 SendMsg *sendmsg_args = reinterpret_cast<SendMsg *>(args);
600 if (sendmsg_args->msg->msg_iovlen == 1 &&
601 !sendmsg_args->msg->msg_control) {
602 // Further down in the code, this sendmsg() call will be simplified to
603 // a sendto() call. Make sure we already compute the correct value for
604 // numExtraData, as it is needed when we allocate "data[]" on the stack.
605 numExtraData = sendmsg_args->msg->msg_namelen;
606 extraDataAddr = sendmsg_args->msg->msg_name;
607 } else {
608 // sendmsg() needs to include some of the extra data so that we can
609 // inspect it in process_socketcall()
610 numExtraData = sizeof(*sendmsg_args->msg) +
611 sendmsg_args->msg->msg_namelen +
612 sendmsg_args->msg->msg_controllen;
613 extraDataAddr = NULL;
614 }
615 }
616 if (call == SYS_RECVMSG) {
617 RecvMsg *recvmsg_args = reinterpret_cast<RecvMsg *>(args);
618 numExtraData = sizeof(*recvmsg_args->msg);
619 extraDataAddr = recvmsg_args->msg;
620 }
621
622 // Set up storage for the request header and copy the data from "args"
623 // into it.
624 struct Request {
625 int sysnum;
626 long long cookie;
627 SocketCall socketcall_req;
628 } __attribute__((packed)) *request;
629 char data[sizeof(struct Request) + numExtraData];
630 request = reinterpret_cast<struct Request *>(data);
631 memcpy(&request->socketcall_req.args, args, socketCallArgInfo[call].len);
632
633 // Simplify send(), sendto() and sendmsg(), if there are simpler equivalent
634 // calls. This allows us to occasionally replace them with calls to write(),
635 // which don't have to be forwarded to the trusted process.
636 SysCalls sys;
637 if (call == SYS_SENDMSG &&
638 request->socketcall_req.args.sendmsg.msg->msg_iovlen == 1 &&
639 !request->socketcall_req.args.sendmsg.msg->msg_control) {
640 // Ordering of these assignments is important, as we are reshuffling
641 // fields inside of a union.
642 call = SYS_SENDTO;
643 request->socketcall_req.args.sendto.flags =
644 request->socketcall_req.args.sendmsg.flags;
645 request->socketcall_req.args.sendto.to =
646 request->socketcall_req.args.sendmsg.msg->msg_name;
647 request->socketcall_req.args.sendto.tolen =
648 request->socketcall_req.args.sendmsg.msg->msg_namelen;
649 request->socketcall_req.args.sendto.len =
650 request->socketcall_req.args.sendmsg.msg->msg_iov->iov_len;
651 request->socketcall_req.args.sendto.buf =
652 request->socketcall_req.args.sendmsg.msg->msg_iov->iov_base;
653 }
654 if (call == SYS_SENDTO && !request->socketcall_req.args.sendto.to) {
655 // sendto() with a NULL address is the same as send()
656 call = SYS_SEND;
657 numExtraData = 0;
658 }
659 if (call == SYS_SEND && !request->socketcall_req.args.send.flags) {
660 // send() with no flags is the same as write(), which is unrestricted
661 // in seccomp mode.
662 Debug::message("Replaced socketcall() with call to write()");
663 ssize_t rc = sys.write(request->socketcall_req.args.send.sockfd,
664 request->socketcall_req.args.send.buf,
665 request->socketcall_req.args.send.len);
666 if (rc < 0) {
667 Debug::elapsed(tm, __NR_socketcall, call);
668 return -sys.my_errno;
669 } else {
670 Debug::elapsed(tm, __NR_socketcall, call);
671 return rc;
672 }
673 }
674
675 // Simplify recv(), and recvfrom(), if there are simpler equivalent calls.
676 // This allows us to occasionally replace them with calls to read(), which
677 // don't have to be forwarded to the trusted process.
678 // We cannot simplify recvmsg() to recvfrom(), recv() or read(), as we do
679 // not know whether the caller needs us to set msg->msg_flags.
680 if (call == SYS_RECVFROM && !request->socketcall_req.args.recvfrom.from) {
681 // recvfrom() with a NULL address buffer is the same as recv()
682 call = SYS_RECV;
683 }
684 if (call == SYS_RECV && !request->socketcall_req.args.recv.flags) {
685 // recv() with no flags is the same as read(), which is unrestricted
686 // in seccomp mode.
687 Debug::message("Replaced socketcall() with call to read()");
688 ssize_t rc = sys.read(request->socketcall_req.args.recv.sockfd,
689 request->socketcall_req.args.recv.buf,
690 request->socketcall_req.args.recv.len);
691 if (rc < 0) {
692 Debug::elapsed(tm, __NR_socketcall, call);
693 return -sys.my_errno;
694 } else {
695 Debug::elapsed(tm, __NR_socketcall, call);
696 return rc;
697 }
698 }
699
700 // Fill in the rest of the request header.
701 request->sysnum = __NR_socketcall;
702 request->cookie = cookie();
703 request->socketcall_req.call = call;
704 request->socketcall_req.arg_ptr = args;
705 int padding = sizeof(request->socketcall_req.args) -
706 socketCallArgInfo[call].len;
707 if (padding > 0) {
708 memset((char *)(&request->socketcall_req.args + 1) - padding, 0, padding);
709 }
710 if (call == SYS_SENDMSG) {
711 // for sendmsg() we include the (optional) destination address, and the
712 // (optional) control data in the payload.
713 SendMsg *sendmsg_args = reinterpret_cast<SendMsg *>(args);
714 memcpy(reinterpret_cast<char *>(
715 memcpy(reinterpret_cast<char *>(
716 memcpy(request + 1, sendmsg_args->msg, sizeof(*sendmsg_args->msg))) +
717 sizeof(*sendmsg_args->msg),
718 sendmsg_args->msg->msg_name, sendmsg_args->msg->msg_namelen)) +
719 sendmsg_args->msg->msg_namelen,
720 sendmsg_args->msg->msg_control, sendmsg_args->msg->msg_controllen);
721 } else if (extraDataAddr) {
722 memcpy(request + 1, extraDataAddr, numExtraData);
723 }
724
725 // Send request to trusted process and collect response from trusted thread.
726 long rc;
727 ssize_t len = sizeof(struct Request) + numExtraData;
728 if (write(sys, processFdPub(), data, len) != len ||
729 read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) {
730 die("Failed to forward socketcall() request [sandbox]");
731 }
732 Debug::elapsed(tm, __NR_socketcall, call);
733 return rc;
734 }
735
736 bool Sandbox::process_socketcall(int parentMapsFd, int sandboxFd,
737 int threadFdPub, int threadFd,
738 SecureMem::Args* mem) {
739 // Read request
740 SocketCall socketcall_req;
741 SysCalls sys;
742 if (read(sys, sandboxFd, &socketcall_req, sizeof(socketcall_req)) !=
743 sizeof(socketcall_req)) {
744 die("Failed to read parameters for socketcall() [process]");
745 }
746
747 // sandbox_socketcall() should never send us an unexpected "call" opcode.
748 // If it did, something went very wrong and we better terminate the process.
749 if (socketcall_req.call < SYS_SOCKET || socketcall_req.call > SYS_ACCEPT4) {
750 die("Unexpected socketcall() [process]");
751 }
752
753 // Check if this particular operation carries an extra payload.
754 socklen_t numExtraData = 0;
755 if (socketCallArgInfo[socketcall_req.call].lengthOff) {
756 memcpy(&numExtraData,
757 reinterpret_cast<char *>(&socketcall_req) +
758 socketCallArgInfo[socketcall_req.call].lengthOff,
759 sizeof(socklen_t));
760 } else if (socketcall_req.call == SYS_SENDMSG) {
761 numExtraData = sizeof(*socketcall_req.args.sendmsg.msg);
762 } else if (socketcall_req.call == SYS_RECVMSG) {
763 numExtraData = sizeof(*socketcall_req.args.recvmsg.msg);
764 }
765
766 // Verify that the length for the payload is reasonable. We don't want to
767 // blow up our stack, and excessive (or negative) buffer sizes are almost
768 // certainly a bug.
769 if (numExtraData > 4096) {
770 die("Unexpected size for socketcall() payload [process]");
771 }
772
773 // Read the extra payload, if any.
774 char extra[numExtraData];
775 if (numExtraData) {
776 if (read(sys, sandboxFd, extra, numExtraData) != (ssize_t)numExtraData) {
777 die("Failed to read socketcall() payload [process]");
778 }
779 }
780
781 // sendmsg() has another level of indirection and can carry even more payload
782 ssize_t numSendmsgExtra = 0;
783 if (socketcall_req.call == SYS_SENDMSG) {
784 struct msghdr* msg = reinterpret_cast<struct msghdr*>(extra);
785 if (msg->msg_namelen > 4096 || msg->msg_controllen > 4096) {
786 die("Unexpected size for socketcall() payload [process]");
787 }
788 numSendmsgExtra = msg->msg_namelen + msg->msg_controllen;
789 }
790 char sendmsgExtra[numSendmsgExtra];
791 if (numSendmsgExtra) {
792 if (read(sys, sandboxFd, sendmsgExtra, numSendmsgExtra) !=
793 numSendmsgExtra) {
794 die("Failed to read socketcall() payload [process]");
795 }
796 }
797
798 int rc = -EINVAL;
799 switch (socketcall_req.call) {
800 case SYS_SOCKET:
801 // The sandbox does not allow creation of any new sockets.
802 goto deny;
803 case SYS_BIND:
804 // The sandbox does not allow binding an address to a socket.
805 goto deny;
806 case SYS_CONNECT:
807 // The sandbox does not allow connecting a socket.
808 goto deny;
809 case SYS_LISTEN:
810 // The sandbox does not allow a socket to enter listening state.
811 goto deny;
812 case SYS_ACCEPT4:
813 case SYS_ACCEPT:
814 // If the sandbox obtained a socket that is already in the listening
815 // state (e.g. because somebody sent it a suitable file descriptor), it
816 // is permissible to call accept().
817
818 accept_simple:
819 // None of the parameters need to be checked, so it is OK to refer
820 // to the parameter block created by the untrusted code.
821 SecureMem::sendSystemCall(threadFdPub, false, -1, mem, __NR_socketcall,
822 socketcall_req.call, socketcall_req.arg_ptr);
823 return true;
824 case SYS_GETSOCKNAME:
825 case SYS_GETPEERNAME:
826 // Querying the local and the remote name is not considered security
827 // sensitive for the purposes of the sandbox.
828 goto accept_simple;
829 case SYS_SOCKETPAIR:
830 // Socket pairs are connected to each other and not considered
831 // security sensitive.
832 goto accept_simple;
833 case SYS_SENDTO:
834 if (socketcall_req.args.sendto.to) {
835 // The sandbox does not allow sending to arbitrary addresses.
836 goto deny;
837 }
838 // Fall through
839 case SYS_SEND:
840 if (socketcall_req.args.send.flags &
841 ~(MSG_CONFIRM|MSG_DONTWAIT|MSG_EOR|MSG_MORE|MSG_NOSIGNAL|MSG_OOB)) {
842 // Unsupported flag encountered. Deny the call.
843 goto deny;
844 }
845 // Sending data on a connected socket is similar to calling write().
846 // Allow it.
847
848 accept_complex:
849 // The parameter block contains potentially security critical information
850 // that should not be tampered with after it has been inspected. Copy it
851 // into the write-protected securely shared memory before telling the
852 // trusted thread to execute the socket call.
853 SecureMem::lockSystemCall(parentMapsFd, mem);
854 memcpy(mem->pathname, &socketcall_req.args, sizeof(socketcall_req.args));
855 SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem,
856 __NR_socketcall, socketcall_req.call,
857 mem->pathname - (char*)mem + (char*)mem->self);
858 return true;
859 case SYS_RECVFROM:
860 // While we do not anticipate any particular need to receive data on
861 // unconnected sockets, there is no particular risk in doing so.
862 // Fall through
863 case SYS_RECV:
864 if (socketcall_req.args.recv.flags &
865 ~(MSG_DONTWAIT|MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_WAITALL)) {
866 // Unsupported flag encountered. Deny the call.
867 goto deny;
868 }
869 // Receiving data on a connected socket is similar to calling read().
870 // Allow it.
871 goto accept_complex;
872 case SYS_SHUTDOWN:
873 // Shutting down a socket is always OK.
874 goto accept_simple;
875 case SYS_SETSOCKOPT:
876 switch (socketcall_req.args.setsockopt.level) {
877 case SOL_SOCKET:
878 switch (socketcall_req.args.setsockopt.optname) {
879 case SO_KEEPALIVE:
880 case SO_LINGER:
881 case SO_OOBINLINE:
882 case SO_RCVBUF:
883 case SO_RCVLOWAT:
884 case SO_SNDLOWAT:
885 case SO_RCVTIMEO:
886 case SO_SNDTIMEO:
887 case SO_REUSEADDR:
888 case SO_SNDBUF:
889 case SO_TIMESTAMP:
890 goto accept_complex;
891 default:
892 break;
893 }
894 break;
895 case IPPROTO_TCP:
896 switch (socketcall_req.args.setsockopt.optname) {
897 case TCP_CORK:
898 case TCP_DEFER_ACCEPT:
899 case TCP_INFO:
900 case TCP_KEEPCNT:
901 case TCP_KEEPIDLE:
902 case TCP_KEEPINTVL:
903 case TCP_LINGER2:
904 case TCP_MAXSEG:
905 case TCP_NODELAY:
906 case TCP_QUICKACK:
907 case TCP_SYNCNT:
908 case TCP_WINDOW_CLAMP:
909 goto accept_complex;
910 default:
911 break;
912 }
913 break;
914 default:
915 break;
916 }
917 goto deny;
918 case SYS_GETSOCKOPT:
919 switch (socketcall_req.args.getsockopt.level) {
920 case SOL_SOCKET:
921 switch (socketcall_req.args.getsockopt.optname) {
922 case SO_ACCEPTCONN:
923 case SO_ERROR:
924 case SO_KEEPALIVE:
925 case SO_LINGER:
926 case SO_OOBINLINE:
927 case SO_RCVBUF:
928 case SO_RCVLOWAT:
929 case SO_SNDLOWAT:
930 case SO_RCVTIMEO:
931 case SO_SNDTIMEO:
932 case SO_REUSEADDR:
933 case SO_SNDBUF:
934 case SO_TIMESTAMP:
935 case SO_TYPE:
936 goto accept_complex;
937 default:
938 break;
939 }
940 break;
941 case IPPROTO_TCP:
942 switch (socketcall_req.args.getsockopt.optname) {
943 case TCP_CORK:
944 case TCP_DEFER_ACCEPT:
945 case TCP_INFO:
946 case TCP_KEEPCNT:
947 case TCP_KEEPIDLE:
948 case TCP_KEEPINTVL:
949 case TCP_LINGER2:
950 case TCP_MAXSEG:
951 case TCP_NODELAY:
952 case TCP_QUICKACK:
953 case TCP_SYNCNT:
954 case TCP_WINDOW_CLAMP:
955 goto accept_complex;
956 default:
957 break;
958 }
959 break;
960 default:
961 break;
962 }
963 goto deny;
964 case SYS_SENDMSG: {
965 struct msghdr* msg = reinterpret_cast<struct msghdr*>(extra);
966
967 if (sizeof(socketcall_req.args) + sizeof(*msg) + numSendmsgExtra >
968 sizeof(mem->pathname)) {
969 goto deny;
970 }
971
972 if (msg->msg_namelen ||
973 (socketcall_req.args.sendmsg.flags &
974 ~(MSG_CONFIRM|MSG_DONTWAIT|MSG_EOR|MSG_MORE|MSG_NOSIGNAL|MSG_OOB))){
975 goto deny;
976 }
977
978 // The trusted process receives file handles when a new untrusted thread
979 // gets created. We have security checks in place that prevent any
980 // critical information from being tampered with during thread creation.
981 // But if we disallowed passing of file handles, this would add an extra
982 // hurdle for an attacker.
983 // Unfortunately, for now, this is not possible as Chrome's
984 // base::SendRecvMsg() needs the ability to pass file handles.
985 if (msg->msg_controllen) {
986 msg->msg_control = sendmsgExtra + msg->msg_namelen;
987 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
988 do {
989 if (cmsg->cmsg_level != SOL_SOCKET ||
990 cmsg->cmsg_type != SCM_RIGHTS) {
991 goto deny;
992 }
993 } while ((cmsg = CMSG_NXTHDR(msg, cmsg)) != NULL);
994 }
995
996 // This must be a locked system call, because we have to ensure that
997 // the untrusted code does not tamper with the msghdr after we have
998 // examined it.
999 SecureMem::lockSystemCall(parentMapsFd, mem);
1000 socketcall_req.args.sendmsg.msg =
1001 reinterpret_cast<struct msghdr*>(mem->pathname +
1002 sizeof(socketcall_req.args) -
1003 (char*)mem + (char*)mem->self);
1004 memcpy(mem->pathname, &socketcall_req.args, sizeof(socketcall_req.args));
1005 if (numSendmsgExtra) {
1006 if (msg->msg_namelen > 0) {
1007 msg->msg_name = const_cast<struct msghdr*>(
1008 socketcall_req.args.sendmsg.msg) + 1;
1009 }
1010 if (msg->msg_controllen > 0) {
1011 msg->msg_control = (char *)(
1012 socketcall_req.args.sendmsg.msg + 1) + msg->msg_namelen;
1013 }
1014 memcpy(mem->pathname + sizeof(socketcall_req.args) + sizeof(*msg),
1015 sendmsgExtra, numSendmsgExtra);
1016 }
1017 memcpy(mem->pathname + sizeof(socketcall_req.args), msg, sizeof(*msg));
1018 SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem,
1019 __NR_socketcall, socketcall_req.call,
1020 mem->pathname - (char*)mem + (char*)mem->self);
1021 return true;
1022 }
1023 case SYS_RECVMSG:
1024 // Receiving messages is general not security critical.
1025 if (socketcall_req.args.recvmsg.flags &
1026 ~(MSG_DONTWAIT|MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_WAITALL)) {
1027 goto deny;
1028 }
1029 goto accept_complex;
1030 default:
1031 deny:
1032 SecureMem::abandonSystemCall(threadFd, rc);
1033 return false;
1034 }
1035 }
1036
1037 #endif
1038
1039 } // namespace
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp/sigprocmask.cc ('k') | sandbox/linux/seccomp/stat.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698