1 // Copyright 2014 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/syscall_broker/broker_client.h"
10 #include <sys/socket.h>
11 #include <sys/types.h>
13 #include "build/build_config.h"
14 #include "base/logging.h"
15 #include "base/pickle.h"
16 #include "base/posix/unix_domain_socket_linux.h"
17 #include "sandbox/linux/syscall_broker/broker_channel.h"
18 #include "sandbox/linux/syscall_broker/broker_common.h"
19 #include "sandbox/linux/syscall_broker/broker_policy.h"
21 #if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC)
22 #define MSG_CMSG_CLOEXEC 0x40000000
27 namespace syscall_broker
{
29 // Make a remote system call over IPC for syscalls that take a path and flags
30 // as arguments, currently open() and access().
31 // Will return -errno like a real system call.
32 // This function needs to be async signal safe.
33 int BrokerClient::PathAndFlagsSyscall(IPCCommand syscall_type
,
36 int recvmsg_flags
= 0;
37 RAW_CHECK(syscall_type
== COMMAND_OPEN
|| syscall_type
== COMMAND_ACCESS
);
41 // For this "remote system call" to work, we need to handle any flag that
42 // cannot be sent over a Unix socket in a special way.
43 // See the comments around kCurrentProcessOpenFlagsMask.
44 if (syscall_type
== COMMAND_OPEN
&& (flags
& kCurrentProcessOpenFlagsMask
)) {
45 // This implementation only knows about O_CLOEXEC, someone needs to look at
46 // this code if other flags are added.
47 RAW_CHECK(kCurrentProcessOpenFlagsMask
== O_CLOEXEC
);
48 recvmsg_flags
|= MSG_CMSG_CLOEXEC
;
52 // There is no point in forwarding a request that we know will be denied.
53 // Of course, the real security check needs to be on the other side of the
55 if (fast_check_in_client_
) {
56 if (syscall_type
== COMMAND_OPEN
&&
57 !broker_policy_
.GetFileNameIfAllowedToOpen(
58 pathname
, flags
, NULL
/* file_to_open */,
59 NULL
/* unlink_after_open */)) {
60 return -broker_policy_
.denied_errno();
62 if (syscall_type
== COMMAND_ACCESS
&&
63 !broker_policy_
.GetFileNameIfAllowedToAccess(pathname
, flags
, NULL
)) {
64 return -broker_policy_
.denied_errno();
68 base::Pickle write_pickle
;
69 write_pickle
.WriteInt(syscall_type
);
70 write_pickle
.WriteString(pathname
);
71 write_pickle
.WriteInt(flags
);
72 RAW_CHECK(write_pickle
.size() <= kMaxMessageLength
);
75 uint8_t reply_buf
[kMaxMessageLength
];
77 // Send a request (in write_pickle) as well that will include a new
78 // temporary socketpair (created internally by SendRecvMsg()).
79 // Then read the reply on this new socketpair in reply_buf and put an
80 // eventual attached file descriptor in |returned_fd|.
81 ssize_t msg_len
= base::UnixDomainSocket::SendRecvMsgWithFlags(
82 ipc_channel_
.get(), reply_buf
, sizeof(reply_buf
), recvmsg_flags
,
83 &returned_fd
, write_pickle
);
85 if (!quiet_failures_for_tests_
)
86 RAW_LOG(ERROR
, "Could not make request to broker process");
90 base::Pickle
read_pickle(reinterpret_cast<char*>(reply_buf
), msg_len
);
91 base::PickleIterator
iter(read_pickle
);
92 int return_value
= -1;
93 // Now deserialize the return value and eventually return the file
95 if (iter
.ReadInt(&return_value
)) {
96 switch (syscall_type
) {
98 // We should never have a fd to return.
99 RAW_CHECK(returned_fd
== -1);
102 if (return_value
< 0) {
103 RAW_CHECK(returned_fd
== -1);
106 // We have a real file descriptor to return.
107 RAW_CHECK(returned_fd
>= 0);
111 RAW_LOG(ERROR
, "Unsupported command");
115 RAW_LOG(ERROR
, "Could not read pickle");
121 BrokerClient::BrokerClient(const BrokerPolicy
& broker_policy
,
122 BrokerChannel::EndPoint ipc_channel
,
123 bool fast_check_in_client
,
124 bool quiet_failures_for_tests
)
125 : broker_policy_(broker_policy
),
126 ipc_channel_(ipc_channel
.Pass()),
127 fast_check_in_client_(fast_check_in_client
),
128 quiet_failures_for_tests_(quiet_failures_for_tests
) {
131 BrokerClient::~BrokerClient() {
134 int BrokerClient::Access(const char* pathname
, int mode
) const {
135 return PathAndFlagsSyscall(COMMAND_ACCESS
, pathname
, mode
);
138 int BrokerClient::Open(const char* pathname
, int flags
) const {
139 return PathAndFlagsSyscall(COMMAND_OPEN
, pathname
, flags
);
142 } // namespace syscall_broker
144 } // namespace sandbox