Fix a build error
[platform/upstream/chromium.git] / ipc / file_descriptor_set_posix.cc
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.
4
5 #include "ipc/file_descriptor_set_posix.h"
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9
10 #include "base/eintr_wrapper.h"
11 #include "base/logging.h"
12
13 FileDescriptorSet::FileDescriptorSet()
14     : consumed_descriptor_highwater_(0) {
15 }
16
17 FileDescriptorSet::~FileDescriptorSet() {
18   if (consumed_descriptor_highwater_ == descriptors_.size())
19     return;
20
21   LOG(WARNING) << "FileDescriptorSet destroyed with unconsumed descriptors";
22   // We close all the descriptors where the close flag is set. If this
23   // message should have been transmitted, then closing those with close
24   // flags set mirrors the expected behaviour.
25   //
26   // If this message was received with more descriptors than expected
27   // (which could a DOS against the browser by a rogue renderer) then all
28   // the descriptors have their close flag set and we free all the extra
29   // kernel resources.
30   for (unsigned i = consumed_descriptor_highwater_;
31        i < descriptors_.size(); ++i) {
32     if (descriptors_[i].auto_close)
33       if (HANDLE_EINTR(close(descriptors_[i].fd)) < 0)
34         PLOG(ERROR) << "close";
35   }
36 }
37
38 bool FileDescriptorSet::Add(int fd) {
39   if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE)
40     return false;
41
42   struct base::FileDescriptor sd;
43   sd.fd = fd;
44   sd.auto_close = false;
45   descriptors_.push_back(sd);
46   return true;
47 }
48
49 bool FileDescriptorSet::AddAndAutoClose(int fd) {
50   if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE)
51     return false;
52
53   struct base::FileDescriptor sd;
54   sd.fd = fd;
55   sd.auto_close = true;
56   descriptors_.push_back(sd);
57   DCHECK(descriptors_.size() <= MAX_DESCRIPTORS_PER_MESSAGE);
58   return true;
59 }
60
61 int FileDescriptorSet::GetDescriptorAt(unsigned index) const {
62   if (index >= descriptors_.size())
63     return -1;
64
65   // We should always walk the descriptors in order, so it's reasonable to
66   // enforce this. Consider the case where a compromised renderer sends us
67   // the following message:
68   //
69   //   ExampleMsg:
70   //     num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
71   //
72   // Here the renderer sent us a message which should have a descriptor, but
73   // actually sent two in an attempt to fill our fd table and kill us. By
74   // setting the index of the descriptor in the message to 1 (it should be
75   // 0), we would record a highwater of 1 and then consider all the
76   // descriptors to have been used.
77   //
78   // So we can either track of the use of each descriptor in a bitset, or we
79   // can enforce that we walk the indexes strictly in order.
80   //
81   // There's one more wrinkle: When logging messages, we may reparse them. So
82   // we have an exception: When the consumed_descriptor_highwater_ is at the
83   // end of the array and index 0 is requested, we reset the highwater value.
84   if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size())
85     consumed_descriptor_highwater_ = 0;
86
87   if (index != consumed_descriptor_highwater_)
88     return -1;
89
90   consumed_descriptor_highwater_ = index + 1;
91   return descriptors_[index].fd;
92 }
93
94 void FileDescriptorSet::GetDescriptors(int* buffer) const {
95   for (std::vector<base::FileDescriptor>::const_iterator
96        i = descriptors_.begin(); i != descriptors_.end(); ++i) {
97     *(buffer++) = i->fd;
98   }
99 }
100
101 bool FileDescriptorSet::ContainsDirectoryDescriptor() const {
102   struct stat st;
103
104   for (std::vector<base::FileDescriptor>::const_iterator
105        i = descriptors_.begin(); i != descriptors_.end(); ++i) {
106     if (fstat(i->fd, &st) == 0 && S_ISDIR(st.st_mode))
107       return true;
108   }
109
110   return false;
111 }
112
113 void FileDescriptorSet::CommitAll() {
114   for (std::vector<base::FileDescriptor>::iterator
115        i = descriptors_.begin(); i != descriptors_.end(); ++i) {
116     if (i->auto_close)
117       if (HANDLE_EINTR(close(i->fd)) < 0)
118         PLOG(ERROR) << "close";
119   }
120   descriptors_.clear();
121   consumed_descriptor_highwater_ = 0;
122 }
123
124 void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) {
125   DCHECK_LE(count, MAX_DESCRIPTORS_PER_MESSAGE);
126   DCHECK_EQ(descriptors_.size(), 0u);
127   DCHECK_EQ(consumed_descriptor_highwater_, 0u);
128
129   descriptors_.reserve(count);
130   for (unsigned i = 0; i < count; ++i) {
131     struct base::FileDescriptor sd;
132     sd.fd = buffer[i];
133     sd.auto_close = true;
134     descriptors_.push_back(sd);
135   }
136 }