Home | History | Annotate | Download | only in ipc
      1 // Copyright (c) 2011 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 "ipc/ipc_message_attachment_set.h"
      6 
      7 #include <stddef.h>
      8 
      9 #include <algorithm>
     10 
     11 #include "base/logging.h"
     12 #include "base/posix/eintr_wrapper.h"
     13 #include "build/build_config.h"
     14 #include "ipc/brokerable_attachment.h"
     15 #include "ipc/ipc_message_attachment.h"
     16 
     17 #if defined(OS_POSIX)
     18 #include <sys/stat.h>
     19 #include <sys/types.h>
     20 #include <unistd.h>
     21 #include "ipc/ipc_platform_file_attachment_posix.h"
     22 #endif // OS_POSIX
     23 
     24 namespace IPC {
     25 
     26 namespace {
     27 
     28 unsigned count_attachments_of_type(
     29     const std::vector<scoped_refptr<MessageAttachment>>& attachments,
     30     MessageAttachment::Type type) {
     31   unsigned count = 0;
     32   for (const scoped_refptr<MessageAttachment>& attachment : attachments) {
     33     if (attachment->GetType() == type)
     34       ++count;
     35   }
     36   return count;
     37 }
     38 
     39 }  // namespace
     40 
     41 MessageAttachmentSet::MessageAttachmentSet()
     42     : consumed_descriptor_highwater_(0) {
     43 }
     44 
     45 MessageAttachmentSet::~MessageAttachmentSet() {
     46   if (consumed_descriptor_highwater_ == num_non_brokerable_attachments())
     47     return;
     48 
     49   // We close all the owning descriptors. If this message should have
     50   // been transmitted, then closing those with close flags set mirrors
     51   // the expected behaviour.
     52   //
     53   // If this message was received with more descriptors than expected
     54   // (which could a DOS against the browser by a rogue renderer) then all
     55   // the descriptors have their close flag set and we free all the extra
     56   // kernel resources.
     57   LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed descriptors: "
     58                << consumed_descriptor_highwater_ << "/" << num_descriptors();
     59 }
     60 
     61 unsigned MessageAttachmentSet::num_descriptors() const {
     62   return count_attachments_of_type(attachments_,
     63                                    MessageAttachment::TYPE_PLATFORM_FILE);
     64 }
     65 
     66 unsigned MessageAttachmentSet::num_mojo_handles() const {
     67   return count_attachments_of_type(attachments_,
     68                                    MessageAttachment::TYPE_MOJO_HANDLE);
     69 }
     70 
     71 unsigned MessageAttachmentSet::num_brokerable_attachments() const {
     72   return static_cast<unsigned>(brokerable_attachments_.size());
     73 }
     74 
     75 unsigned MessageAttachmentSet::num_non_brokerable_attachments() const {
     76   return static_cast<unsigned>(attachments_.size());
     77 }
     78 
     79 unsigned MessageAttachmentSet::size() const {
     80   return static_cast<unsigned>(attachments_.size() +
     81                                brokerable_attachments_.size());
     82 }
     83 
     84 bool MessageAttachmentSet::AddAttachment(
     85     scoped_refptr<MessageAttachment> attachment,
     86     size_t* index,
     87     bool* brokerable) {
     88 #if defined(OS_POSIX)
     89   if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE &&
     90       num_descriptors() == kMaxDescriptorsPerMessage) {
     91     DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
     92     return false;
     93   }
     94 #endif
     95 
     96   switch (attachment->GetType()) {
     97     case MessageAttachment::TYPE_PLATFORM_FILE:
     98     case MessageAttachment::TYPE_MOJO_HANDLE:
     99       attachments_.push_back(attachment);
    100       *index = attachments_.size() - 1;
    101       *brokerable = false;
    102       return true;
    103     case MessageAttachment::TYPE_BROKERABLE_ATTACHMENT:
    104       BrokerableAttachment* brokerable_attachment =
    105           static_cast<BrokerableAttachment*>(attachment.get());
    106       scoped_refptr<BrokerableAttachment> a(brokerable_attachment);
    107       brokerable_attachments_.push_back(a);
    108       *index = brokerable_attachments_.size() - 1;
    109       *brokerable = true;
    110       return true;
    111   }
    112   return false;
    113 }
    114 
    115 bool MessageAttachmentSet::AddAttachment(
    116     scoped_refptr<MessageAttachment> attachment) {
    117   bool brokerable;
    118   size_t index;
    119   return AddAttachment(attachment, &index, &brokerable);
    120 }
    121 
    122 scoped_refptr<MessageAttachment>
    123 MessageAttachmentSet::GetNonBrokerableAttachmentAt(unsigned index) {
    124   if (index >= num_non_brokerable_attachments()) {
    125     DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
    126                   << num_non_brokerable_attachments();
    127     return scoped_refptr<MessageAttachment>();
    128   }
    129 
    130   // We should always walk the descriptors in order, so it's reasonable to
    131   // enforce this. Consider the case where a compromised renderer sends us
    132   // the following message:
    133   //
    134   //   ExampleMsg:
    135   //     num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
    136   //
    137   // Here the renderer sent us a message which should have a descriptor, but
    138   // actually sent two in an attempt to fill our fd table and kill us. By
    139   // setting the index of the descriptor in the message to 1 (it should be
    140   // 0), we would record a highwater of 1 and then consider all the
    141   // descriptors to have been used.
    142   //
    143   // So we can either track of the use of each descriptor in a bitset, or we
    144   // can enforce that we walk the indexes strictly in order.
    145   //
    146   // There's one more wrinkle: When logging messages, we may reparse them. So
    147   // we have an exception: When the consumed_descriptor_highwater_ is at the
    148   // end of the array and index 0 is requested, we reset the highwater value.
    149   // TODO(morrita): This is absurd. This "wringle" disallow to introduce clearer
    150   // ownership model. Only client is NaclIPCAdapter. See crbug.com/415294
    151   if (index == 0 &&
    152       consumed_descriptor_highwater_ == num_non_brokerable_attachments()) {
    153     consumed_descriptor_highwater_ = 0;
    154   }
    155 
    156   if (index != consumed_descriptor_highwater_)
    157     return scoped_refptr<MessageAttachment>();
    158 
    159   consumed_descriptor_highwater_ = index + 1;
    160 
    161   return attachments_[index];
    162 }
    163 
    164 scoped_refptr<MessageAttachment>
    165 MessageAttachmentSet::GetBrokerableAttachmentAt(unsigned index) {
    166   if (index >= num_brokerable_attachments()) {
    167     DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
    168                   << num_brokerable_attachments();
    169     return scoped_refptr<MessageAttachment>();
    170   }
    171 
    172   scoped_refptr<BrokerableAttachment> brokerable_attachment(
    173       brokerable_attachments_[index]);
    174   return scoped_refptr<MessageAttachment>(brokerable_attachment.get());
    175 }
    176 
    177 void MessageAttachmentSet::CommitAllDescriptors() {
    178   attachments_.clear();
    179   consumed_descriptor_highwater_ = 0;
    180 }
    181 
    182 std::vector<scoped_refptr<IPC::BrokerableAttachment>>
    183 MessageAttachmentSet::GetBrokerableAttachments() const {
    184   return brokerable_attachments_;
    185 }
    186 
    187 void MessageAttachmentSet::ReplacePlaceholderWithAttachment(
    188     const scoped_refptr<BrokerableAttachment>& attachment) {
    189   DCHECK_NE(BrokerableAttachment::PLACEHOLDER, attachment->GetBrokerableType());
    190   for (auto it = brokerable_attachments_.begin();
    191        it != brokerable_attachments_.end(); ++it) {
    192     if ((*it)->GetBrokerableType() == BrokerableAttachment::PLACEHOLDER &&
    193         (*it)->GetIdentifier() == attachment->GetIdentifier()) {
    194       *it = attachment;
    195       return;
    196     }
    197   }
    198 
    199   // This function should only be called if there is a placeholder ready to be
    200   // replaced.
    201   NOTREACHED();
    202 }
    203 
    204 #if defined(OS_POSIX)
    205 
    206 void MessageAttachmentSet::PeekDescriptors(base::PlatformFile* buffer) const {
    207   for (size_t i = 0; i != attachments_.size(); ++i)
    208     buffer[i] = internal::GetPlatformFile(attachments_[i]);
    209 }
    210 
    211 bool MessageAttachmentSet::ContainsDirectoryDescriptor() const {
    212   struct stat st;
    213 
    214   for (auto i = attachments_.begin(); i != attachments_.end(); ++i) {
    215     if (fstat(internal::GetPlatformFile(*i), &st) == 0 && S_ISDIR(st.st_mode))
    216       return true;
    217   }
    218 
    219   return false;
    220 }
    221 
    222 void MessageAttachmentSet::ReleaseFDsToClose(
    223     std::vector<base::PlatformFile>* fds) {
    224   for (size_t i = 0; i < attachments_.size(); ++i) {
    225     internal::PlatformFileAttachment* file =
    226         static_cast<internal::PlatformFileAttachment*>(attachments_[i].get());
    227     if (file->Owns())
    228       fds->push_back(file->TakePlatformFile());
    229   }
    230 
    231   CommitAllDescriptors();
    232 }
    233 
    234 void MessageAttachmentSet::AddDescriptorsToOwn(const base::PlatformFile* buffer,
    235                                                unsigned count) {
    236   DCHECK(count <= kMaxDescriptorsPerMessage);
    237   DCHECK_EQ(num_descriptors(), 0u);
    238   DCHECK_EQ(consumed_descriptor_highwater_, 0u);
    239 
    240   attachments_.reserve(count);
    241   for (unsigned i = 0; i < count; ++i)
    242     AddAttachment(
    243         new internal::PlatformFileAttachment(base::ScopedFD(buffer[i])));
    244 }
    245 
    246 #endif  // OS_POSIX
    247 
    248 }  // namespace IPC
    249 
    250 
    251