ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial