1 // Copyright (c) 2012 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.
5 #include "sandbox/linux/services/broker_process.h"
9 #include <sys/socket.h>
11 #include <sys/syscall.h>
12 #include <sys/types.h>
20 #include "base/basictypes.h"
21 #include "base/callback.h"
22 #include "base/compiler_specific.h"
23 #include "base/files/scoped_file.h"
24 #include "base/logging.h"
25 #include "base/memory/scoped_vector.h"
26 #include "base/pickle.h"
27 #include "base/posix/eintr_wrapper.h"
28 #include "base/posix/unix_domain_socket_linux.h"
29 #include "base/process/process_metrics.h"
30 #include "base/third_party/valgrind/valgrind.h"
31 #include "build/build_config.h"
32 #include "sandbox/linux/services/linux_syscalls.h"
34 #if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC)
35 #define MSG_CMSG_CLOEXEC 0x40000000
40 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND
; }
42 // A little open(2) wrapper to handle some oddities for us. In the general case
43 // make a direct system call since we want to keep in control of the broker
44 // process' system calls profile to be able to loosely sandbox it.
45 int sys_open(const char* pathname
, int flags
) {
46 // Always pass a defined |mode| in case flags mistakenly contains O_CREAT.
48 if (IsRunningOnValgrind()) {
49 // Valgrind does not support AT_FDCWD, just use libc's open() in this case.
50 return open(pathname
, flags
, mode
);
52 return syscall(__NR_openat
, AT_FDCWD
, pathname
, flags
, mode
);
56 static const size_t kMaxMessageLength
= 4096;
58 // Some flags are local to the current process and cannot be sent over a Unix
59 // socket. They need special treatment from the client.
60 // O_CLOEXEC is tricky because in theory another thread could call execve()
61 // before special treatment is made on the client, so a client needs to call
62 // recvmsg(2) with MSG_CMSG_CLOEXEC.
63 // To make things worse, there are two CLOEXEC related flags, FD_CLOEXEC (see
64 // F_GETFD in fcntl(2)) and O_CLOEXEC (see F_GETFL in fcntl(2)). O_CLOEXEC
65 // doesn't affect the semantics on execve(), it's merely a note that the
66 // descriptor was originally opened with O_CLOEXEC as a flag. And it is sent
67 // over unix sockets just fine, so a receiver that would (incorrectly) look at
68 // O_CLOEXEC instead of FD_CLOEXEC may be tricked in thinking that the file
69 // descriptor will or won't be closed on execve().
70 static const int kCurrentProcessOpenFlagsMask
= O_CLOEXEC
;
72 // Check whether |requested_filename| is in |allowed_file_names|.
73 // See GetFileNameIfAllowedToOpen() for an explanation of |file_to_open|.
74 // async signal safe if |file_to_open| is NULL.
75 // TODO(jln): assert signal safety.
76 bool GetFileNameInWhitelist(const std::vector
<std::string
>& allowed_file_names
,
77 const char* requested_filename
,
78 const char** file_to_open
) {
79 if (file_to_open
&& *file_to_open
) {
80 // Make sure that callers never pass a non-empty string. In case callers
81 // wrongly forget to check the return value and look at the string
82 // instead, this could catch bugs.
83 RAW_LOG(FATAL
, "*file_to_open should be NULL");
87 // Look for |requested_filename| in |allowed_file_names|.
88 // We don't use ::find() because it takes a std::string and
89 // the conversion allocates memory.
90 std::vector
<std::string
>::const_iterator it
;
91 for (it
= allowed_file_names
.begin(); it
!= allowed_file_names
.end(); it
++) {
92 if (strcmp(requested_filename
, it
->c_str()) == 0) {
94 *file_to_open
= it
->c_str();
101 // We maintain a list of flags that have been reviewed for "sanity" and that
102 // we're ok to allow in the broker.
103 // I.e. here is where we wouldn't add O_RESET_FILE_SYSTEM.
104 bool IsAllowedOpenFlags(int flags
) {
105 // First, check the access mode.
106 const int access_mode
= flags
& O_ACCMODE
;
107 if (access_mode
!= O_RDONLY
&& access_mode
!= O_WRONLY
&&
108 access_mode
!= O_RDWR
) {
112 // We only support a 2-parameters open, so we forbid O_CREAT.
113 if (flags
& O_CREAT
) {
117 // Some flags affect the behavior of the current process. We don't support
118 // them and don't allow them for now.
119 if (flags
& kCurrentProcessOpenFlagsMask
)
122 // Now check that all the flags are known to us.
123 const int creation_and_status_flags
= flags
& ~O_ACCMODE
;
125 const int known_flags
=
126 O_APPEND
| O_ASYNC
| O_CLOEXEC
| O_CREAT
| O_DIRECT
|
127 O_DIRECTORY
| O_EXCL
| O_LARGEFILE
| O_NOATIME
| O_NOCTTY
|
128 O_NOFOLLOW
| O_NONBLOCK
| O_NDELAY
| O_SYNC
| O_TRUNC
;
130 const int unknown_flags
= ~known_flags
;
131 const bool has_unknown_flags
= creation_and_status_flags
& unknown_flags
;
132 return !has_unknown_flags
;
139 BrokerProcess::BrokerProcess(int denied_errno
,
140 const std::vector
<std::string
>& allowed_r_files
,
141 const std::vector
<std::string
>& allowed_w_files
,
142 bool fast_check_in_client
,
143 bool quiet_failures_for_tests
)
144 : denied_errno_(denied_errno
),
147 fast_check_in_client_(fast_check_in_client
),
148 quiet_failures_for_tests_(quiet_failures_for_tests
),
150 allowed_r_files_(allowed_r_files
),
151 allowed_w_files_(allowed_w_files
),
152 ipc_socketpair_(-1) {
155 BrokerProcess::~BrokerProcess() {
156 if (initialized_
&& ipc_socketpair_
!= -1) {
157 // Closing the socket should be enough to notify the child to die,
158 // unless it has been duplicated.
159 PCHECK(0 == IGNORE_EINTR(close(ipc_socketpair_
)));
160 PCHECK(0 == kill(broker_pid_
, SIGKILL
));
161 siginfo_t process_info
;
163 int ret
= HANDLE_EINTR(waitid(P_PID
, broker_pid_
, &process_info
, WEXITED
));
168 bool BrokerProcess::Init(
169 const base::Callback
<bool(void)>& broker_process_init_callback
) {
170 CHECK(!initialized_
);
172 // Use SOCK_SEQPACKET, because we need to preserve message boundaries
173 // but we also want to be notified (recvmsg should return and not block)
174 // when the connection has been broken (one of the processes died).
175 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, socket_pair
)) {
176 LOG(ERROR
) << "Failed to create socketpair";
180 #if !defined(THREAD_SANITIZER)
181 DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
183 int child_pid
= fork();
184 if (child_pid
== -1) {
185 close(socket_pair
[0]);
186 close(socket_pair
[1]);
190 // We are the parent and we have just forked our broker process.
191 close(socket_pair
[0]);
192 // We should only be able to write to the IPC channel. We'll always send
193 // a new file descriptor to receive the reply on.
194 shutdown(socket_pair
[1], SHUT_RD
);
195 ipc_socketpair_
= socket_pair
[1];
197 broker_pid_
= child_pid
;
201 // We are the broker.
202 close(socket_pair
[1]);
203 // We should only be able to read from this IPC channel. We will send our
204 // replies on a new file descriptor attached to the requests.
205 shutdown(socket_pair
[0], SHUT_WR
);
206 ipc_socketpair_
= socket_pair
[0];
208 CHECK(broker_process_init_callback
.Run());
218 int BrokerProcess::Access(const char* pathname
, int mode
) const {
219 return PathAndFlagsSyscall(kCommandAccess
, pathname
, mode
);
222 int BrokerProcess::Open(const char* pathname
, int flags
) const {
223 return PathAndFlagsSyscall(kCommandOpen
, pathname
, flags
);
226 // Make a remote system call over IPC for syscalls that take a path and flags
227 // as arguments, currently open() and access().
228 // Will return -errno like a real system call.
229 // This function needs to be async signal safe.
230 int BrokerProcess::PathAndFlagsSyscall(enum IPCCommands syscall_type
,
231 const char* pathname
, int flags
) const {
232 int recvmsg_flags
= 0;
233 RAW_CHECK(initialized_
); // async signal safe CHECK().
234 RAW_CHECK(syscall_type
== kCommandOpen
|| syscall_type
== kCommandAccess
);
238 // For this "remote system call" to work, we need to handle any flag that
239 // cannot be sent over a Unix socket in a special way.
240 // See the comments around kCurrentProcessOpenFlagsMask.
241 if (syscall_type
== kCommandOpen
&& (flags
& kCurrentProcessOpenFlagsMask
)) {
242 // This implementation only knows about O_CLOEXEC, someone needs to look at
243 // this code if other flags are added.
244 RAW_CHECK(kCurrentProcessOpenFlagsMask
== O_CLOEXEC
);
245 recvmsg_flags
|= MSG_CMSG_CLOEXEC
;
249 // There is no point in forwarding a request that we know will be denied.
250 // Of course, the real security check needs to be on the other side of the
252 if (fast_check_in_client_
) {
253 if (syscall_type
== kCommandOpen
&&
254 !GetFileNameIfAllowedToOpen(pathname
, flags
, NULL
)) {
255 return -denied_errno_
;
257 if (syscall_type
== kCommandAccess
&&
258 !GetFileNameIfAllowedToAccess(pathname
, flags
, NULL
)) {
259 return -denied_errno_
;
264 write_pickle
.WriteInt(syscall_type
);
265 write_pickle
.WriteString(pathname
);
266 write_pickle
.WriteInt(flags
);
267 RAW_CHECK(write_pickle
.size() <= kMaxMessageLength
);
269 int returned_fd
= -1;
270 uint8_t reply_buf
[kMaxMessageLength
];
272 // Send a request (in write_pickle) as well that will include a new
273 // temporary socketpair (created internally by SendRecvMsg()).
274 // Then read the reply on this new socketpair in reply_buf and put an
275 // eventual attached file descriptor in |returned_fd|.
276 ssize_t msg_len
= UnixDomainSocket::SendRecvMsgWithFlags(ipc_socketpair_
,
283 if (!quiet_failures_for_tests_
)
284 RAW_LOG(ERROR
, "Could not make request to broker process");
288 Pickle
read_pickle(reinterpret_cast<char*>(reply_buf
), msg_len
);
289 PickleIterator
iter(read_pickle
);
290 int return_value
= -1;
291 // Now deserialize the return value and eventually return the file
293 if (read_pickle
.ReadInt(&iter
, &return_value
)) {
294 switch (syscall_type
) {
296 // We should never have a fd to return.
297 RAW_CHECK(returned_fd
== -1);
300 if (return_value
< 0) {
301 RAW_CHECK(returned_fd
== -1);
304 // We have a real file descriptor to return.
305 RAW_CHECK(returned_fd
>= 0);
309 RAW_LOG(ERROR
, "Unsupported command");
313 RAW_LOG(ERROR
, "Could not read pickle");
319 // Handle a request on the IPC channel ipc_socketpair_.
320 // A request should have a file descriptor attached on which we will reply and
321 // that we will then close.
322 // A request should start with an int that will be used as the command type.
323 bool BrokerProcess::HandleRequest() const {
324 ScopedVector
<base::ScopedFD
> fds
;
325 char buf
[kMaxMessageLength
];
327 const ssize_t msg_len
= UnixDomainSocket::RecvMsg(ipc_socketpair_
, buf
,
330 if (msg_len
== 0 || (msg_len
== -1 && errno
== ECONNRESET
)) {
331 // EOF from our parent, or our parent died, we should die.
335 // The parent should send exactly one file descriptor, on which we
336 // will write the reply.
337 // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'.
338 if (msg_len
< 0 || fds
.size() != 1 || fds
[0]->get() < 0) {
339 PLOG(ERROR
) << "Error reading message from the client";
343 base::ScopedFD
temporary_ipc(fds
[0]->Pass());
345 Pickle
pickle(buf
, msg_len
);
346 PickleIterator
iter(pickle
);
348 if (pickle
.ReadInt(&iter
, &command_type
)) {
350 // Go through all the possible IPC messages.
351 switch (command_type
) {
354 // We reply on the file descriptor sent to us via the IPC channel.
355 r
= HandleRemoteCommand(static_cast<IPCCommands
>(command_type
),
356 temporary_ipc
.get(), pickle
, iter
);
366 LOG(ERROR
) << "Error parsing IPC request";
370 // Handle a |command_type| request contained in |read_pickle| and send the reply
372 // Currently kCommandOpen and kCommandAccess are supported.
373 bool BrokerProcess::HandleRemoteCommand(IPCCommands command_type
, int reply_ipc
,
374 const Pickle
& read_pickle
,
375 PickleIterator iter
) const {
376 // Currently all commands have two arguments: filename and flags.
377 std::string requested_filename
;
379 if (!read_pickle
.ReadString(&iter
, &requested_filename
) ||
380 !read_pickle
.ReadInt(&iter
, &flags
)) {
385 std::vector
<int> opened_files
;
387 switch (command_type
) {
389 AccessFileForIPC(requested_filename
, flags
, &write_pickle
);
392 OpenFileForIPC(requested_filename
, flags
, &write_pickle
, &opened_files
);
395 LOG(ERROR
) << "Invalid IPC command";
399 CHECK_LE(write_pickle
.size(), kMaxMessageLength
);
400 ssize_t sent
= UnixDomainSocket::SendMsg(reply_ipc
, write_pickle
.data(),
401 write_pickle
.size(), opened_files
);
403 // Close anything we have opened in this process.
404 for (std::vector
<int>::iterator it
= opened_files
.begin();
405 it
!= opened_files
.end(); ++it
) {
406 int ret
= IGNORE_EINTR(close(*it
));
407 DCHECK(!ret
) << "Could not close file descriptor";
411 LOG(ERROR
) << "Could not send IPC reply";
417 // Perform access(2) on |requested_filename| with mode |mode| if allowed by our
418 // policy. Write the syscall return value (-errno) to |write_pickle|.
419 void BrokerProcess::AccessFileForIPC(const std::string
& requested_filename
,
420 int mode
, Pickle
* write_pickle
) const {
421 DCHECK(write_pickle
);
422 const char* file_to_access
= NULL
;
423 const bool safe_to_access_file
= GetFileNameIfAllowedToAccess(
424 requested_filename
.c_str(), mode
, &file_to_access
);
426 if (safe_to_access_file
) {
427 CHECK(file_to_access
);
428 int access_ret
= access(file_to_access
, mode
);
429 int access_errno
= errno
;
431 write_pickle
->WriteInt(0);
433 write_pickle
->WriteInt(-access_errno
);
435 write_pickle
->WriteInt(-denied_errno_
);
439 // Open |requested_filename| with |flags| if allowed by our policy.
440 // Write the syscall return value (-errno) to |write_pickle| and append
441 // a file descriptor to |opened_files| if relevant.
442 void BrokerProcess::OpenFileForIPC(const std::string
& requested_filename
,
443 int flags
, Pickle
* write_pickle
,
444 std::vector
<int>* opened_files
) const {
445 DCHECK(write_pickle
);
446 DCHECK(opened_files
);
447 const char* file_to_open
= NULL
;
448 const bool safe_to_open_file
= GetFileNameIfAllowedToOpen(
449 requested_filename
.c_str(), flags
, &file_to_open
);
451 if (safe_to_open_file
) {
453 int opened_fd
= sys_open(file_to_open
, flags
);
455 write_pickle
->WriteInt(-errno
);
458 opened_files
->push_back(opened_fd
);
459 write_pickle
->WriteInt(0);
462 write_pickle
->WriteInt(-denied_errno_
);
467 // Check if calling access() should be allowed on |requested_filename| with
468 // mode |requested_mode|.
469 // Note: access() being a system call to check permissions, this can get a bit
470 // confusing. We're checking if calling access() should even be allowed with
471 // the same policy we would use for open().
472 // If |file_to_access| is not NULL, we will return the matching pointer from
473 // the whitelist. For paranoia a caller should then use |file_to_access|. See
474 // GetFileNameIfAllowedToOpen() fore more explanation.
475 // return true if calling access() on this file should be allowed, false
477 // Async signal safe if and only if |file_to_access| is NULL.
478 bool BrokerProcess::GetFileNameIfAllowedToAccess(const char* requested_filename
,
479 int requested_mode
, const char** file_to_access
) const {
480 // First, check if |requested_mode| is existence, ability to read or ability
481 // to write. We do not support X_OK.
482 if (requested_mode
!= F_OK
&&
483 requested_mode
& ~(R_OK
| W_OK
)) {
486 switch (requested_mode
) {
488 // We allow to check for file existence if we can either read or write.
489 return GetFileNameInWhitelist(allowed_r_files_
, requested_filename
,
491 GetFileNameInWhitelist(allowed_w_files_
, requested_filename
,
494 return GetFileNameInWhitelist(allowed_r_files_
, requested_filename
,
497 return GetFileNameInWhitelist(allowed_w_files_
, requested_filename
,
501 bool allowed_for_read_and_write
=
502 GetFileNameInWhitelist(allowed_r_files_
, requested_filename
, NULL
) &&
503 GetFileNameInWhitelist(allowed_w_files_
, requested_filename
,
505 return allowed_for_read_and_write
;
512 // Check if |requested_filename| can be opened with flags |requested_flags|.
513 // If |file_to_open| is not NULL, we will return the matching pointer from the
514 // whitelist. For paranoia, a caller should then use |file_to_open| rather
515 // than |requested_filename|, so that it never attempts to open an
516 // attacker-controlled file name, even if an attacker managed to fool the
517 // string comparison mechanism.
518 // Return true if opening should be allowed, false otherwise.
519 // Async signal safe if and only if |file_to_open| is NULL.
520 bool BrokerProcess::GetFileNameIfAllowedToOpen(const char* requested_filename
,
521 int requested_flags
, const char** file_to_open
) const {
522 if (!IsAllowedOpenFlags(requested_flags
)) {
525 switch (requested_flags
& O_ACCMODE
) {
527 return GetFileNameInWhitelist(allowed_r_files_
, requested_filename
,
530 return GetFileNameInWhitelist(allowed_w_files_
, requested_filename
,
534 bool allowed_for_read_and_write
=
535 GetFileNameInWhitelist(allowed_r_files_
, requested_filename
, NULL
) &&
536 GetFileNameInWhitelist(allowed_w_files_
, requested_filename
,
538 return allowed_for_read_and_write
;
545 } // namespace sandbox.