• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ipc_message_attachment.h"
15 
16 namespace IPC {
17 
18 namespace {
19 
count_attachments_of_type(const std::vector<scoped_refptr<MessageAttachment>> & attachments,MessageAttachment::Type type)20 unsigned count_attachments_of_type(
21     const std::vector<scoped_refptr<MessageAttachment>>& attachments,
22     MessageAttachment::Type type) {
23   unsigned count = 0;
24   for (const scoped_refptr<MessageAttachment>& attachment : attachments) {
25     if (attachment->GetType() == type)
26       ++count;
27   }
28   return count;
29 }
30 
31 }  // namespace
32 
MessageAttachmentSet()33 MessageAttachmentSet::MessageAttachmentSet()
34     : consumed_descriptor_highwater_(0) {
35 }
36 
~MessageAttachmentSet()37 MessageAttachmentSet::~MessageAttachmentSet() {
38   if (consumed_descriptor_highwater_ == size())
39     return;
40 
41   // We close all the owning descriptors. If this message should have
42   // been transmitted, then closing those with close flags set mirrors
43   // the expected behaviour.
44   //
45   // If this message was received with more descriptors than expected
46   // (which could a DOS against the browser by a rogue renderer) then all
47   // the descriptors have their close flag set and we free all the extra
48   // kernel resources.
49   LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed attachments: "
50                << consumed_descriptor_highwater_ << "/" << size();
51 }
52 
num_descriptors() const53 unsigned MessageAttachmentSet::num_descriptors() const {
54   return count_attachments_of_type(attachments_,
55                                    MessageAttachment::Type::PLATFORM_FILE);
56 }
57 
size() const58 unsigned MessageAttachmentSet::size() const {
59   return static_cast<unsigned>(attachments_.size());
60 }
61 
AddAttachment(scoped_refptr<MessageAttachment> attachment,size_t * index)62 bool MessageAttachmentSet::AddAttachment(
63     scoped_refptr<MessageAttachment> attachment,
64     size_t* index) {
65 #if defined(OS_POSIX)
66   if (attachment->GetType() == MessageAttachment::Type::PLATFORM_FILE &&
67       num_descriptors() == kMaxDescriptorsPerMessage) {
68     DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
69     return false;
70   }
71 #endif
72 
73   switch (attachment->GetType()) {
74     case MessageAttachment::Type::PLATFORM_FILE:
75     case MessageAttachment::Type::MOJO_HANDLE:
76     case MessageAttachment::Type::WIN_HANDLE:
77     case MessageAttachment::Type::MACH_PORT:
78       attachments_.push_back(attachment);
79       *index = attachments_.size() - 1;
80       return true;
81   }
82   return false;
83 }
84 
AddAttachment(scoped_refptr<MessageAttachment> attachment)85 bool MessageAttachmentSet::AddAttachment(
86     scoped_refptr<MessageAttachment> attachment) {
87   size_t index;
88   return AddAttachment(attachment, &index);
89 }
90 
GetAttachmentAt(unsigned index)91 scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
92     unsigned index) {
93   if (index >= size()) {
94     DLOG(WARNING) << "Accessing out of bound index:" << index << "/" << size();
95     return scoped_refptr<MessageAttachment>();
96   }
97 
98   // We should always walk the descriptors in order, so it's reasonable to
99   // enforce this. Consider the case where a compromised renderer sends us
100   // the following message:
101   //
102   //   ExampleMsg:
103   //     num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
104   //
105   // Here the renderer sent us a message which should have a descriptor, but
106   // actually sent two in an attempt to fill our fd table and kill us. By
107   // setting the index of the descriptor in the message to 1 (it should be
108   // 0), we would record a highwater of 1 and then consider all the
109   // descriptors to have been used.
110   //
111   // So we can either track of the use of each descriptor in a bitset, or we
112   // can enforce that we walk the indexes strictly in order.
113   //
114   // There's one more wrinkle: When logging messages, we may reparse them. So
115   // we have an exception: When the consumed_descriptor_highwater_ is at the
116   // end of the array and index 0 is requested, we reset the highwater value.
117   // TODO(morrita): This is absurd. This "wringle" disallow to introduce clearer
118   // ownership model. Only client is NaclIPCAdapter. See crbug.com/415294
119   if (index == 0 && consumed_descriptor_highwater_ == size()) {
120     consumed_descriptor_highwater_ = 0;
121   }
122 
123   if (index != consumed_descriptor_highwater_)
124     return scoped_refptr<MessageAttachment>();
125 
126   consumed_descriptor_highwater_ = index + 1;
127 
128   return attachments_[index];
129 }
130 
CommitAllDescriptors()131 void MessageAttachmentSet::CommitAllDescriptors() {
132   attachments_.clear();
133   consumed_descriptor_highwater_ = 0;
134 }
135 
136 }  // namespace IPC
137