xref: /aosp_15_r20/external/libchrome/ipc/ipc_message_attachment_set.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_message_attachment_set.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
8*635a8641SAndroid Build Coastguard Worker 
9*635a8641SAndroid Build Coastguard Worker #include <algorithm>
10*635a8641SAndroid Build Coastguard Worker 
11*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/posix/eintr_wrapper.h"
13*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
14*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_message_attachment.h"
15*635a8641SAndroid Build Coastguard Worker 
16*635a8641SAndroid Build Coastguard Worker namespace IPC {
17*635a8641SAndroid Build Coastguard Worker 
18*635a8641SAndroid Build Coastguard Worker namespace {
19*635a8641SAndroid Build Coastguard Worker 
count_attachments_of_type(const std::vector<scoped_refptr<MessageAttachment>> & attachments,MessageAttachment::Type type)20*635a8641SAndroid Build Coastguard Worker unsigned count_attachments_of_type(
21*635a8641SAndroid Build Coastguard Worker     const std::vector<scoped_refptr<MessageAttachment>>& attachments,
22*635a8641SAndroid Build Coastguard Worker     MessageAttachment::Type type) {
23*635a8641SAndroid Build Coastguard Worker   unsigned count = 0;
24*635a8641SAndroid Build Coastguard Worker   for (const scoped_refptr<MessageAttachment>& attachment : attachments) {
25*635a8641SAndroid Build Coastguard Worker     if (attachment->GetType() == type)
26*635a8641SAndroid Build Coastguard Worker       ++count;
27*635a8641SAndroid Build Coastguard Worker   }
28*635a8641SAndroid Build Coastguard Worker   return count;
29*635a8641SAndroid Build Coastguard Worker }
30*635a8641SAndroid Build Coastguard Worker 
31*635a8641SAndroid Build Coastguard Worker }  // namespace
32*635a8641SAndroid Build Coastguard Worker 
MessageAttachmentSet()33*635a8641SAndroid Build Coastguard Worker MessageAttachmentSet::MessageAttachmentSet()
34*635a8641SAndroid Build Coastguard Worker     : consumed_descriptor_highwater_(0) {
35*635a8641SAndroid Build Coastguard Worker }
36*635a8641SAndroid Build Coastguard Worker 
~MessageAttachmentSet()37*635a8641SAndroid Build Coastguard Worker MessageAttachmentSet::~MessageAttachmentSet() {
38*635a8641SAndroid Build Coastguard Worker   if (consumed_descriptor_highwater_ == size())
39*635a8641SAndroid Build Coastguard Worker     return;
40*635a8641SAndroid Build Coastguard Worker 
41*635a8641SAndroid Build Coastguard Worker   // We close all the owning descriptors. If this message should have
42*635a8641SAndroid Build Coastguard Worker   // been transmitted, then closing those with close flags set mirrors
43*635a8641SAndroid Build Coastguard Worker   // the expected behaviour.
44*635a8641SAndroid Build Coastguard Worker   //
45*635a8641SAndroid Build Coastguard Worker   // If this message was received with more descriptors than expected
46*635a8641SAndroid Build Coastguard Worker   // (which could a DOS against the browser by a rogue renderer) then all
47*635a8641SAndroid Build Coastguard Worker   // the descriptors have their close flag set and we free all the extra
48*635a8641SAndroid Build Coastguard Worker   // kernel resources.
49*635a8641SAndroid Build Coastguard Worker   LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed attachments: "
50*635a8641SAndroid Build Coastguard Worker                << consumed_descriptor_highwater_ << "/" << size();
51*635a8641SAndroid Build Coastguard Worker }
52*635a8641SAndroid Build Coastguard Worker 
num_descriptors() const53*635a8641SAndroid Build Coastguard Worker unsigned MessageAttachmentSet::num_descriptors() const {
54*635a8641SAndroid Build Coastguard Worker   return count_attachments_of_type(attachments_,
55*635a8641SAndroid Build Coastguard Worker                                    MessageAttachment::Type::PLATFORM_FILE);
56*635a8641SAndroid Build Coastguard Worker }
57*635a8641SAndroid Build Coastguard Worker 
size() const58*635a8641SAndroid Build Coastguard Worker unsigned MessageAttachmentSet::size() const {
59*635a8641SAndroid Build Coastguard Worker   return static_cast<unsigned>(attachments_.size());
60*635a8641SAndroid Build Coastguard Worker }
61*635a8641SAndroid Build Coastguard Worker 
AddAttachment(scoped_refptr<MessageAttachment> attachment,size_t * index)62*635a8641SAndroid Build Coastguard Worker bool MessageAttachmentSet::AddAttachment(
63*635a8641SAndroid Build Coastguard Worker     scoped_refptr<MessageAttachment> attachment,
64*635a8641SAndroid Build Coastguard Worker     size_t* index) {
65*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX) || defined(OS_FUCHSIA)
66*635a8641SAndroid Build Coastguard Worker   if (attachment->GetType() == MessageAttachment::Type::PLATFORM_FILE &&
67*635a8641SAndroid Build Coastguard Worker       num_descriptors() == kMaxDescriptorsPerMessage) {
68*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
69*635a8641SAndroid Build Coastguard Worker     return false;
70*635a8641SAndroid Build Coastguard Worker   }
71*635a8641SAndroid Build Coastguard Worker #endif
72*635a8641SAndroid Build Coastguard Worker 
73*635a8641SAndroid Build Coastguard Worker   switch (attachment->GetType()) {
74*635a8641SAndroid Build Coastguard Worker     case MessageAttachment::Type::PLATFORM_FILE:
75*635a8641SAndroid Build Coastguard Worker     case MessageAttachment::Type::MOJO_HANDLE:
76*635a8641SAndroid Build Coastguard Worker     case MessageAttachment::Type::WIN_HANDLE:
77*635a8641SAndroid Build Coastguard Worker     case MessageAttachment::Type::MACH_PORT:
78*635a8641SAndroid Build Coastguard Worker     case MessageAttachment::Type::FUCHSIA_HANDLE:
79*635a8641SAndroid Build Coastguard Worker       attachments_.push_back(attachment);
80*635a8641SAndroid Build Coastguard Worker       *index = attachments_.size() - 1;
81*635a8641SAndroid Build Coastguard Worker       return true;
82*635a8641SAndroid Build Coastguard Worker   }
83*635a8641SAndroid Build Coastguard Worker   return false;
84*635a8641SAndroid Build Coastguard Worker }
85*635a8641SAndroid Build Coastguard Worker 
AddAttachment(scoped_refptr<MessageAttachment> attachment)86*635a8641SAndroid Build Coastguard Worker bool MessageAttachmentSet::AddAttachment(
87*635a8641SAndroid Build Coastguard Worker     scoped_refptr<MessageAttachment> attachment) {
88*635a8641SAndroid Build Coastguard Worker   size_t index;
89*635a8641SAndroid Build Coastguard Worker   return AddAttachment(attachment, &index);
90*635a8641SAndroid Build Coastguard Worker }
91*635a8641SAndroid Build Coastguard Worker 
GetAttachmentAt(unsigned index)92*635a8641SAndroid Build Coastguard Worker scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
93*635a8641SAndroid Build Coastguard Worker     unsigned index) {
94*635a8641SAndroid Build Coastguard Worker   if (index >= size()) {
95*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Accessing out of bound index:" << index << "/" << size();
96*635a8641SAndroid Build Coastguard Worker     return scoped_refptr<MessageAttachment>();
97*635a8641SAndroid Build Coastguard Worker   }
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker   // We should always walk the descriptors in order, so it's reasonable to
100*635a8641SAndroid Build Coastguard Worker   // enforce this. Consider the case where a compromised renderer sends us
101*635a8641SAndroid Build Coastguard Worker   // the following message:
102*635a8641SAndroid Build Coastguard Worker   //
103*635a8641SAndroid Build Coastguard Worker   //   ExampleMsg:
104*635a8641SAndroid Build Coastguard Worker   //     num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
105*635a8641SAndroid Build Coastguard Worker   //
106*635a8641SAndroid Build Coastguard Worker   // Here the renderer sent us a message which should have a descriptor, but
107*635a8641SAndroid Build Coastguard Worker   // actually sent two in an attempt to fill our fd table and kill us. By
108*635a8641SAndroid Build Coastguard Worker   // setting the index of the descriptor in the message to 1 (it should be
109*635a8641SAndroid Build Coastguard Worker   // 0), we would record a highwater of 1 and then consider all the
110*635a8641SAndroid Build Coastguard Worker   // descriptors to have been used.
111*635a8641SAndroid Build Coastguard Worker   //
112*635a8641SAndroid Build Coastguard Worker   // So we can either track of the use of each descriptor in a bitset, or we
113*635a8641SAndroid Build Coastguard Worker   // can enforce that we walk the indexes strictly in order.
114*635a8641SAndroid Build Coastguard Worker   if (index == 0 && consumed_descriptor_highwater_ == size()) {
115*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Attempted to double-read a message attachment, "
116*635a8641SAndroid Build Coastguard Worker                      "returning a nullptr";
117*635a8641SAndroid Build Coastguard Worker   }
118*635a8641SAndroid Build Coastguard Worker 
119*635a8641SAndroid Build Coastguard Worker   if (index != consumed_descriptor_highwater_)
120*635a8641SAndroid Build Coastguard Worker     return scoped_refptr<MessageAttachment>();
121*635a8641SAndroid Build Coastguard Worker 
122*635a8641SAndroid Build Coastguard Worker   consumed_descriptor_highwater_ = index + 1;
123*635a8641SAndroid Build Coastguard Worker 
124*635a8641SAndroid Build Coastguard Worker   return attachments_[index];
125*635a8641SAndroid Build Coastguard Worker }
126*635a8641SAndroid Build Coastguard Worker 
CommitAllDescriptors()127*635a8641SAndroid Build Coastguard Worker void MessageAttachmentSet::CommitAllDescriptors() {
128*635a8641SAndroid Build Coastguard Worker   attachments_.clear();
129*635a8641SAndroid Build Coastguard Worker   consumed_descriptor_highwater_ = 0;
130*635a8641SAndroid Build Coastguard Worker }
131*635a8641SAndroid Build Coastguard Worker 
132*635a8641SAndroid Build Coastguard Worker }  // namespace IPC
133