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. 36 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 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 133 BrokerClient::~BrokerClient() { 134 } 135 136 int BrokerClient::Access(const char* pathname, int mode) const { 137 return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode); 138 } 139 140 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