1 // Copyright (c) 2006-2008 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.
5 #include "ipc/file_descriptor_set_posix.h"
7 #include "base/eintr_wrapper.h"
8 #include "base/logging.h"
10 FileDescriptorSet::FileDescriptorSet()
11 : consumed_descriptor_highwater_(0) {
14 FileDescriptorSet::~FileDescriptorSet() {
15 if (consumed_descriptor_highwater_
== descriptors_
.size())
18 LOG(WARNING
) << "FileDescriptorSet destroyed with unconsumed descriptors";
19 // We close all the descriptors where the close flag is set. If this
20 // message should have been transmitted, then closing those with close
21 // flags set mirrors the expected behaviour.
23 // If this message was received with more descriptors than expected
24 // (which could a DOS against the browser by a rogue renderer) then all
25 // the descriptors have their close flag set and we free all the extra
27 for (unsigned i
= consumed_descriptor_highwater_
;
28 i
< descriptors_
.size(); ++i
) {
29 if (descriptors_
[i
].auto_close
)
30 HANDLE_EINTR(close(descriptors_
[i
].fd
));
34 bool FileDescriptorSet::Add(int fd
) {
35 if (descriptors_
.size() == MAX_DESCRIPTORS_PER_MESSAGE
)
38 struct base::FileDescriptor sd
;
40 sd
.auto_close
= false;
41 descriptors_
.push_back(sd
);
45 bool FileDescriptorSet::AddAndAutoClose(int fd
) {
46 if (descriptors_
.size() == MAX_DESCRIPTORS_PER_MESSAGE
)
49 struct base::FileDescriptor sd
;
52 descriptors_
.push_back(sd
);
53 DCHECK(descriptors_
.size() <= MAX_DESCRIPTORS_PER_MESSAGE
);
57 int FileDescriptorSet::GetDescriptorAt(unsigned index
) const {
58 if (index
>= descriptors_
.size())
61 // We should always walk the descriptors in order, so it's reasonable to
62 // enforce this. Consider the case where a compromised renderer sends us
63 // the following message:
66 // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
68 // Here the renderer sent us a message which should have a descriptor, but
69 // actually sent two in an attempt to fill our fd table and kill us. By
70 // setting the index of the descriptor in the message to 1 (it should be
71 // 0), we would record a highwater of 1 and then consider all the
72 // descriptors to have been used.
74 // So we can either track of the use of each descriptor in a bitset, or we
75 // can enforce that we walk the indexes strictly in order.
77 // There's one more wrinkle: When logging messages, we may reparse them. So
78 // we have an exception: When the consumed_descriptor_highwater_ is at the
79 // end of the array and index 0 is requested, we reset the highwater value.
80 if (index
== 0 && consumed_descriptor_highwater_
== descriptors_
.size())
81 consumed_descriptor_highwater_
= 0;
83 if (index
!= consumed_descriptor_highwater_
)
86 consumed_descriptor_highwater_
= index
+ 1;
87 return descriptors_
[index
].fd
;
90 void FileDescriptorSet::GetDescriptors(int* buffer
) const {
91 for (std::vector
<base::FileDescriptor
>::const_iterator
92 i
= descriptors_
.begin(); i
!= descriptors_
.end(); ++i
) {
97 void FileDescriptorSet::CommitAll() {
98 for (std::vector
<base::FileDescriptor
>::iterator
99 i
= descriptors_
.begin(); i
!= descriptors_
.end(); ++i
) {
101 HANDLE_EINTR(close(i
->fd
));
103 descriptors_
.clear();
104 consumed_descriptor_highwater_
= 0;
107 void FileDescriptorSet::SetDescriptors(const int* buffer
, unsigned count
) {
108 DCHECK_LE(count
, MAX_DESCRIPTORS_PER_MESSAGE
);
109 DCHECK_EQ(descriptors_
.size(), 0u);
110 DCHECK_EQ(consumed_descriptor_highwater_
, 0u);
112 descriptors_
.reserve(count
);
113 for (unsigned i
= 0; i
< count
; ++i
) {
114 struct base::FileDescriptor sd
;
116 sd
.auto_close
= true;
117 descriptors_
.push_back(sd
);