Home | History | Annotate | Download | only in syscall_broker
      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