1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,121 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "chrome/common/file_descriptor_set_posix.h" 1.9 + 1.10 +#include "base/eintr_wrapper.h" 1.11 +#include "base/logging.h" 1.12 + 1.13 +#include <unistd.h> 1.14 + 1.15 +FileDescriptorSet::FileDescriptorSet() 1.16 + : consumed_descriptor_highwater_(0) { 1.17 +} 1.18 + 1.19 +FileDescriptorSet::~FileDescriptorSet() { 1.20 + if (consumed_descriptor_highwater_ == descriptors_.size()) 1.21 + return; 1.22 + 1.23 + CHROMIUM_LOG(WARNING) << "FileDescriptorSet destroyed with unconsumed descriptors"; 1.24 + // We close all the descriptors where the close flag is set. If this 1.25 + // message should have been transmitted, then closing those with close 1.26 + // flags set mirrors the expected behaviour. 1.27 + // 1.28 + // If this message was received with more descriptors than expected 1.29 + // (which could a DOS against the browser by a rogue renderer) then all 1.30 + // the descriptors have their close flag set and we free all the extra 1.31 + // kernel resources. 1.32 + for (unsigned i = consumed_descriptor_highwater_; 1.33 + i < descriptors_.size(); ++i) { 1.34 + if (descriptors_[i].auto_close) 1.35 + HANDLE_EINTR(close(descriptors_[i].fd)); 1.36 + } 1.37 +} 1.38 + 1.39 +bool FileDescriptorSet::Add(int fd) { 1.40 + if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE) 1.41 + return false; 1.42 + 1.43 + struct base::FileDescriptor sd; 1.44 + sd.fd = fd; 1.45 + sd.auto_close = false; 1.46 + descriptors_.push_back(sd); 1.47 + return true; 1.48 +} 1.49 + 1.50 +bool FileDescriptorSet::AddAndAutoClose(int fd) { 1.51 + if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE) 1.52 + return false; 1.53 + 1.54 + struct base::FileDescriptor sd; 1.55 + sd.fd = fd; 1.56 + sd.auto_close = true; 1.57 + descriptors_.push_back(sd); 1.58 + DCHECK(descriptors_.size() <= MAX_DESCRIPTORS_PER_MESSAGE); 1.59 + return true; 1.60 +} 1.61 + 1.62 +int FileDescriptorSet::GetDescriptorAt(unsigned index) const { 1.63 + if (index >= descriptors_.size()) 1.64 + return -1; 1.65 + 1.66 + // We should always walk the descriptors in order, so it's reasonable to 1.67 + // enforce this. Consider the case where a compromised renderer sends us 1.68 + // the following message: 1.69 + // 1.70 + // ExampleMsg: 1.71 + // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m} 1.72 + // 1.73 + // Here the renderer sent us a message which should have a descriptor, but 1.74 + // actually sent two in an attempt to fill our fd table and kill us. By 1.75 + // setting the index of the descriptor in the message to 1 (it should be 1.76 + // 0), we would record a highwater of 1 and then consider all the 1.77 + // descriptors to have been used. 1.78 + // 1.79 + // So we can either track of the use of each descriptor in a bitset, or we 1.80 + // can enforce that we walk the indexes strictly in order. 1.81 + // 1.82 + // There's one more wrinkle: When logging messages, we may reparse them. So 1.83 + // we have an exception: When the consumed_descriptor_highwater_ is at the 1.84 + // end of the array and index 0 is requested, we reset the highwater value. 1.85 + if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size()) 1.86 + consumed_descriptor_highwater_ = 0; 1.87 + 1.88 + if (index != consumed_descriptor_highwater_) 1.89 + return -1; 1.90 + 1.91 + consumed_descriptor_highwater_ = index + 1; 1.92 + return descriptors_[index].fd; 1.93 +} 1.94 + 1.95 +void FileDescriptorSet::GetDescriptors(int* buffer) const { 1.96 + for (std::vector<base::FileDescriptor>::const_iterator 1.97 + i = descriptors_.begin(); i != descriptors_.end(); ++i) { 1.98 + *(buffer++) = i->fd; 1.99 + } 1.100 +} 1.101 + 1.102 +void FileDescriptorSet::CommitAll() { 1.103 + for (std::vector<base::FileDescriptor>::iterator 1.104 + i = descriptors_.begin(); i != descriptors_.end(); ++i) { 1.105 + if (i->auto_close) 1.106 + HANDLE_EINTR(close(i->fd)); 1.107 + } 1.108 + descriptors_.clear(); 1.109 + consumed_descriptor_highwater_ = 0; 1.110 +} 1.111 + 1.112 +void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) { 1.113 + DCHECK_LE(count, MAX_DESCRIPTORS_PER_MESSAGE); 1.114 + DCHECK_EQ(descriptors_.size(), 0u); 1.115 + DCHECK_EQ(consumed_descriptor_highwater_, 0u); 1.116 + 1.117 + descriptors_.reserve(count); 1.118 + for (unsigned i = 0; i < count; ++i) { 1.119 + struct base::FileDescriptor sd; 1.120 + sd.fd = buffer[i]; 1.121 + sd.auto_close = true; 1.122 + descriptors_.push_back(sd); 1.123 + } 1.124 +}