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