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.
4
5 #include "sandbox/linux/syscall_broker/broker_client.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <sys/socket.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <utility>
15
16 #include "base/logging.h"
17 #include "base/pickle.h"
18 #include "base/posix/unix_domain_socket_linux.h"
19 #include "build/build_config.h"
20 #include "sandbox/linux/syscall_broker/broker_channel.h"
21 #include "sandbox/linux/syscall_broker/broker_common.h"
22 #include "sandbox/linux/syscall_broker/broker_policy.h"
23
24 #if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC)
25 #define MSG_CMSG_CLOEXEC 0x40000000
26 #endif
27
28 namespace sandbox {
29
30 namespace syscall_broker {
31
32 // Make a remote system call over IPC for syscalls that take a path and flags
33 // as arguments, currently open() and access().
34 // Will return -errno like a real system call.
35 // This function needs to be async signal safe.
PathAndFlagsSyscall(IPCCommand syscall_type,const char * pathname,int flags) const36 int BrokerClient::PathAndFlagsSyscall(IPCCommand syscall_type,
37 const char* pathname,
38 int flags) const {
39 int recvmsg_flags = 0;
40 RAW_CHECK(syscall_type == COMMAND_OPEN || syscall_type == COMMAND_ACCESS);
41 if (!pathname)
42 return -EFAULT;
43
44 // For this "remote system call" to work, we need to handle any flag that
45 // cannot be sent over a Unix socket in a special way.
46 // See the comments around kCurrentProcessOpenFlagsMask.
47 if (syscall_type == COMMAND_OPEN && (flags & kCurrentProcessOpenFlagsMask)) {
48 // This implementation only knows about O_CLOEXEC, someone needs to look at
49 // this code if other flags are added.
50 RAW_CHECK(kCurrentProcessOpenFlagsMask == O_CLOEXEC);
51 recvmsg_flags |= MSG_CMSG_CLOEXEC;
52 flags &= ~O_CLOEXEC;
53 }
54
55 // There is no point in forwarding a request that we know will be denied.
56 // Of course, the real security check needs to be on the other side of the
57 // IPC.
58 if (fast_check_in_client_) {
59 if (syscall_type == COMMAND_OPEN &&
60 !broker_policy_.GetFileNameIfAllowedToOpen(
61 pathname, flags, NULL /* file_to_open */,
62 NULL /* unlink_after_open */)) {
63 return -broker_policy_.denied_errno();
64 }
65 if (syscall_type == COMMAND_ACCESS &&
66 !broker_policy_.GetFileNameIfAllowedToAccess(pathname, flags, NULL)) {
67 return -broker_policy_.denied_errno();
68 }
69 }
70
71 base::Pickle write_pickle;
72 write_pickle.WriteInt(syscall_type);
73 write_pickle.WriteString(pathname);
74 write_pickle.WriteInt(flags);
75 RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
76
77 int returned_fd = -1;
78 uint8_t reply_buf[kMaxMessageLength];
79
80 // Send a request (in write_pickle) as well that will include a new
81 // temporary socketpair (created internally by SendRecvMsg()).
82 // Then read the reply on this new socketpair in reply_buf and put an
83 // eventual attached file descriptor in |returned_fd|.
84 ssize_t msg_len = base::UnixDomainSocket::SendRecvMsgWithFlags(
85 ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
86 &returned_fd, write_pickle);
87 if (msg_len <= 0) {
88 if (!quiet_failures_for_tests_)
89 RAW_LOG(ERROR, "Could not make request to broker process");
90 return -ENOMEM;
91 }
92
93 base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
94 base::PickleIterator iter(read_pickle);
95 int return_value = -1;
96 // Now deserialize the return value and eventually return the file
97 // descriptor.
98 if (iter.ReadInt(&return_value)) {
99 switch (syscall_type) {
100 case COMMAND_ACCESS:
101 // We should never have a fd to return.
102 RAW_CHECK(returned_fd == -1);
103 return return_value;
104 case COMMAND_OPEN:
105 if (return_value < 0) {
106 RAW_CHECK(returned_fd == -1);
107 return return_value;
108 } else {
109 // We have a real file descriptor to return.
110 RAW_CHECK(returned_fd >= 0);
111 return returned_fd;
112 }
113 default:
114 RAW_LOG(ERROR, "Unsupported command");
115 return -ENOSYS;
116 }
117 } else {
118 RAW_LOG(ERROR, "Could not read pickle");
119 NOTREACHED();
120 return -ENOMEM;
121 }
122 }
123
BrokerClient(const BrokerPolicy & broker_policy,BrokerChannel::EndPoint ipc_channel,bool fast_check_in_client,bool quiet_failures_for_tests)124 BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
125 BrokerChannel::EndPoint ipc_channel,
126 bool fast_check_in_client,
127 bool quiet_failures_for_tests)
128 : broker_policy_(broker_policy),
129 ipc_channel_(std::move(ipc_channel)),
130 fast_check_in_client_(fast_check_in_client),
131 quiet_failures_for_tests_(quiet_failures_for_tests) {}
132
~BrokerClient()133 BrokerClient::~BrokerClient() {
134 }
135
Access(const char * pathname,int mode) const136 int BrokerClient::Access(const char* pathname, int mode) const {
137 return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode);
138 }
139
Open(const char * pathname,int flags) const140 int BrokerClient::Open(const char* pathname, int flags) const {
141 return PathAndFlagsSyscall(COMMAND_OPEN, pathname, flags);
142 }
143
144 } // namespace syscall_broker
145
146 } // namespace sandbox
147