diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-12 18:09:11 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-12 18:09:11 +0000 |
commit | a17b7ca6d209f26bf96a055aa6a5fa7dbfe68612 (patch) | |
tree | e06d274969cfda7ad27f57c73477bd1015b7aa9e /chrome/common | |
parent | f0d550860b6b9402df5dd5855b885e2e3a9be1d2 (diff) | |
download | chromium_src-a17b7ca6d209f26bf96a055aa6a5fa7dbfe68612.zip chromium_src-a17b7ca6d209f26bf96a055aa6a5fa7dbfe68612.tar.gz chromium_src-a17b7ca6d209f26bf96a055aa6a5fa7dbfe68612.tar.bz2 |
POSIX: Make copies of descriptor_set.[cc|h] in preparation of a rename
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9674 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/file_descriptor_set_posix.cc | 118 | ||||
-rw-r--r-- | chrome/common/file_descriptor_set_posix.h | 108 |
2 files changed, 226 insertions, 0 deletions
diff --git a/chrome/common/file_descriptor_set_posix.cc b/chrome/common/file_descriptor_set_posix.cc new file mode 100644 index 0000000..9b19ef2 --- /dev/null +++ b/chrome/common/file_descriptor_set_posix.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/descriptor_set_posix.h" + +#include "base/logging.h" + +DescriptorSet::DescriptorSet() + : consumed_descriptor_highwater_(0) { +} + +DescriptorSet::~DescriptorSet() { + if (consumed_descriptor_highwater_ == descriptors_.size()) + return; + + LOG(WARNING) << "DescriptorSet destroyed with unconsumed descriptors"; + // We close all the descriptors where the close flag is set. If this + // message should have been transmitted, then closing those with close + // flags set mirrors the expected behaviour. + // + // If this message was received with more descriptors than expected + // (which could a DOS against the browser by a rogue renderer) then all + // the descriptors have their close flag set and we free all the extra + // kernel resources. + for (unsigned i = consumed_descriptor_highwater_; + i < descriptors_.size(); ++i) { + if (descriptors_[i].auto_close) + close(descriptors_[i].fd); + } +} + +bool DescriptorSet::Add(int fd) { + if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE) + return false; + + struct base::FileDescriptor sd; + sd.fd = fd; + sd.auto_close = false; + descriptors_.push_back(sd); + return true; +} + +bool DescriptorSet::AddAndAutoClose(int fd) { + if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE) + return false; + + struct base::FileDescriptor sd; + sd.fd = fd; + sd.auto_close = true; + descriptors_.push_back(sd); + DCHECK(descriptors_.size() <= MAX_DESCRIPTORS_PER_MESSAGE); + return true; +} + +int DescriptorSet::GetDescriptorAt(unsigned index) const { + if (index >= descriptors_.size()) + return -1; + + // We should always walk the descriptors in order, so it's reasonable to + // enforce this. Consider the case where a compromised renderer sends us + // the following message: + // + // ExampleMsg: + // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m} + // + // Here the renderer sent us a message which should have a descriptor, but + // actually sent two in an attempt to fill our fd table and kill us. By + // setting the index of the descriptor in the message to 1 (it should be + // 0), we would record a highwater of 1 and then consider all the + // descriptors to have been used. + // + // So we can either track of the use of each descriptor in a bitset, or we + // can enforce that we walk the indexes strictly in order. + // + // There's one more wrinkle: When logging messages, we may reparse them. So + // we have an exception: When the consumed_descriptor_highwater_ is at the + // end of the array and index 0 is requested, we reset the highwater value. + if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size()) + consumed_descriptor_highwater_ = 0; + + if (index != consumed_descriptor_highwater_) + return -1; + + consumed_descriptor_highwater_ = index + 1; + return descriptors_[index].fd; +} + +void DescriptorSet::GetDescriptors(int* buffer) const { + for (std::vector<base::FileDescriptor>::const_iterator + i = descriptors_.begin(); i != descriptors_.end(); ++i) { + *(buffer++) = i->fd; + } +} + +void DescriptorSet::CommitAll() { + for (std::vector<base::FileDescriptor>::iterator + i = descriptors_.begin(); i != descriptors_.end(); ++i) { + if (i->auto_close) + close(i->fd); + } + descriptors_.clear(); + consumed_descriptor_highwater_ = 0; +} + +void DescriptorSet::SetDescriptors(const int* buffer, unsigned count) { + DCHECK_LE(count, MAX_DESCRIPTORS_PER_MESSAGE); + DCHECK_EQ(descriptors_.size(), 0u); + DCHECK_EQ(consumed_descriptor_highwater_, 0u); + + descriptors_.reserve(count); + for (unsigned i = 0; i < count; ++i) { + struct base::FileDescriptor sd; + sd.fd = buffer[i]; + sd.auto_close = true; + descriptors_.push_back(sd); + } +} diff --git a/chrome/common/file_descriptor_set_posix.h b/chrome/common/file_descriptor_set_posix.h new file mode 100644 index 0000000..1757648 --- /dev/null +++ b/chrome/common/file_descriptor_set_posix.h @@ -0,0 +1,108 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_DESCRIPTOR_SET_POSIX_H_ +#define CHROME_COMMON_DESCRIPTOR_SET_POSIX_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/file_descriptor_posix.h" +#include "base/ref_counted.h" + +// ----------------------------------------------------------------------------- +// A DescriptorSet is an ordered set of POSIX file descriptors. These are +// associated with IPC messages so that descriptors can be transmitted over a +// UNIX domain socket. +// ----------------------------------------------------------------------------- +class DescriptorSet : public base::RefCountedThreadSafe<DescriptorSet> { + public: + DescriptorSet(); + ~DescriptorSet(); + + // This is the maximum number of descriptors per message. We need to know this + // because the control message kernel interface has to be given a buffer which + // is large enough to store all the descriptor numbers. Otherwise the kernel + // tells us that it truncated the control data and the extra descriptors are + // lost. + // + // In debugging mode, it's a fatal error to try and add more than this number + // of descriptors to a DescriptorSet. + enum { + MAX_DESCRIPTORS_PER_MESSAGE = 4, + }; + + // --------------------------------------------------------------------------- + // Interfaces for building during message serialisation... + + // Add a descriptor to the end of the set. Returns false iff the set is full. + bool Add(int fd); + // Add a descriptor to the end of the set and automatically close it after + // transmission. Returns false iff the set is full. + bool AddAndAutoClose(int fd); + + // --------------------------------------------------------------------------- + + + // --------------------------------------------------------------------------- + // Interfaces for accessing during message deserialisation... + + // Return the number of descriptors + unsigned size() const { return descriptors_.size(); } + // Return true if no unconsumed descriptors remain + bool empty() const { return descriptors_.empty(); } + // Fetch the nth descriptor from the beginning of the set. Code using this + // /must/ access the descriptors in order, except that it may wrap from the + // end to index 0 again. + // + // This interface is designed for the deserialising code as it doesn't + // support close flags. + // returns: file descriptor, or -1 on error + int GetDescriptorAt(unsigned n) const; + + // --------------------------------------------------------------------------- + + + // --------------------------------------------------------------------------- + // Interfaces for transmission... + + // Fill an array with file descriptors without 'consuming' them. CommitAll + // must be called after these descriptors have been transmitted. + // buffer: (output) a buffer of, at least, size() integers. + void GetDescriptors(int* buffer) const; + // This must be called after transmitting the descriptors returned by + // GetDescriptors. It marks all the descriptors as consumed and closes those + // which are auto-close. + void CommitAll(); + + // --------------------------------------------------------------------------- + + + // --------------------------------------------------------------------------- + // Interfaces for receiving... + + // Set the contents of the set from the given buffer. This set must be empty + // before calling. The auto-close flag is set on all the descriptors so that + // unconsumed descriptors are closed on destruction. + void SetDescriptors(const int* buffer, unsigned count); + + // --------------------------------------------------------------------------- + + private: + // A vector of descriptors and close flags. If this message is sent, then + // these descriptors are sent as control data. After sending, any descriptors + // with a true flag are closed. If this message has been received, then these + // are the descriptors which were received and all close flags are true. + std::vector<base::FileDescriptor> descriptors_; + + // This contains the index of the next descriptor which should be consumed. + // It's used in a couple of ways. Firstly, at destruction we can check that + // all the descriptors have been read (with GetNthDescriptor). Secondly, we + // can check that they are read in order. + mutable unsigned consumed_descriptor_highwater_; + + DISALLOW_COPY_AND_ASSIGN(DescriptorSet); +}; + +#endif // CHROME_COMMON_FILE_DESCRIPTOR_POSIX_H_ |