Fix crash on app list start page keyboard navigation with <4 apps.
[chromium-blink-merge.git] / sandbox / linux / syscall_broker / broker_client.cc
blob8d04197160a9accdb67c84f2f132811ace873d17
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"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/stat.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
23 #endif
25 namespace sandbox {
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,
34 const char* pathname,
35 int flags) const {
36 int recvmsg_flags = 0;
37 RAW_CHECK(syscall_type == COMMAND_OPEN || syscall_type == COMMAND_ACCESS);
38 if (!pathname)
39 return -EFAULT;
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;
49 flags &= ~O_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
54 // IPC.
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 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);
74 int returned_fd = -1;
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 = UnixDomainSocket::SendRecvMsgWithFlags(
82 ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
83 &returned_fd, write_pickle);
84 if (msg_len <= 0) {
85 if (!quiet_failures_for_tests_)
86 RAW_LOG(ERROR, "Could not make request to broker process");
87 return -ENOMEM;
90 Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
91 PickleIterator iter(read_pickle);
92 int return_value = -1;
93 // Now deserialize the return value and eventually return the file
94 // descriptor.
95 if (iter.ReadInt(&return_value)) {
96 switch (syscall_type) {
97 case COMMAND_ACCESS:
98 // We should never have a fd to return.
99 RAW_CHECK(returned_fd == -1);
100 return return_value;
101 case COMMAND_OPEN:
102 if (return_value < 0) {
103 RAW_CHECK(returned_fd == -1);
104 return return_value;
105 } else {
106 // We have a real file descriptor to return.
107 RAW_CHECK(returned_fd >= 0);
108 return returned_fd;
110 default:
111 RAW_LOG(ERROR, "Unsupported command");
112 return -ENOSYS;
114 } else {
115 RAW_LOG(ERROR, "Could not read pickle");
116 NOTREACHED();
117 return -ENOMEM;
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