tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ipc_message.h (15085B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style license that can be
      5 // found in the LICENSE file.
      6 
      7 #ifndef CHROME_COMMON_IPC_MESSAGE_H__
      8 #define CHROME_COMMON_IPC_MESSAGE_H__
      9 
     10 #include "base/basictypes.h"
     11 #include "base/pickle.h"
     12 #include "mojo/core/ports/user_message.h"
     13 #include "mojo/core/ports/port_ref.h"
     14 #include "mozilla/TimeStamp.h"
     15 #include "mozilla/UniquePtrExtensions.h"
     16 #include "mozilla/ipc/ScopedPort.h"
     17 #include "nsTArray.h"
     18 
     19 namespace mozilla {
     20 
     21 #ifdef FUZZING_SNAPSHOT
     22 namespace fuzzing {
     23 class IPCFuzzController;
     24 }
     25 #endif
     26 
     27 namespace ipc {
     28 class MiniTransceiver;
     29 }
     30 }  // namespace mozilla
     31 
     32 namespace IPC {
     33 
     34 //------------------------------------------------------------------------------
     35 
     36 // Generated by IPDL compiler
     37 bool IPCMessageTypeIsSync(uint32_t aMessageType);
     38 const char* StringFromIPCMessageType(uint32_t aMessageType);
     39 
     40 class Channel;
     41 class Message;
     42 class MessageReader;
     43 class MessageWriter;
     44 struct LogData;
     45 
     46 class Message : public mojo::core::ports::UserMessage, public Pickle {
     47 public:
     48  static const TypeInfo kUserMessageTypeInfo;
     49 
     50  using routeid_t = int64_t;
     51  using msgid_t = uint32_t;
     52  using seqno_t = int64_t;
     53 
     54  enum NestedLevel {
     55    NOT_NESTED = 1,
     56    NESTED_INSIDE_SYNC = 2,
     57    NESTED_INSIDE_CPOW = 3
     58  };
     59 
     60  enum PriorityValue {
     61    NORMAL_PRIORITY = 0,
     62    INPUT_PRIORITY = 1,
     63    VSYNC_PRIORITY = 2,
     64    MEDIUMHIGH_PRIORITY = 3,
     65    CONTROL_PRIORITY = 4,
     66    LOW_PRIORITY = 5,
     67  };
     68 
     69  enum MessageCompression {
     70    COMPRESSION_NONE,
     71    COMPRESSION_ENABLED,
     72    COMPRESSION_ALL
     73  };
     74 
     75  enum Sync {
     76    SYNC = 0,
     77    ASYNC = 1,
     78  };
     79 
     80  enum Constructor {
     81    NOT_CONSTRUCTOR = 0,
     82    CONSTRUCTOR = 1,
     83  };
     84 
     85  enum Reply {
     86    NOT_REPLY = 0,
     87    REPLY = 1,
     88  };
     89 
     90  enum LazySend {
     91    EAGER_SEND = 0,
     92    LAZY_SEND = 1,
     93  };
     94 
     95  // The hard limit of handles or file descriptors allowed in a single message.
     96  static constexpr size_t MAX_DESCRIPTORS_PER_MESSAGE = 32767;
     97 
     98  class HeaderFlags {
     99    friend class Message;
    100 #ifdef FUZZING_SNAPSHOT
    101    // IPCFuzzController calls various private API functions on the header.
    102    friend class mozilla::fuzzing::IPCFuzzController;
    103 #endif
    104 
    105    enum {
    106      NESTED_MASK = 0x0003,
    107      PRIO_MASK = 0x001C,
    108      SYNC_BIT = 0x0020,
    109      REPLY_BIT = 0x0040,
    110      REPLY_ERROR_BIT = 0x0080,
    111      LAZY_SEND_BIT = 0x0100,
    112      COMPRESS_BIT = 0x0200,
    113      COMPRESSALL_BIT = 0x0400,
    114      CONSTRUCTOR_BIT = 0x0800,
    115      RELAY_BIT = 0x1000,
    116    };
    117 
    118   public:
    119    constexpr HeaderFlags() : mFlags(NOT_NESTED) {}
    120 
    121    explicit constexpr HeaderFlags(NestedLevel level) : mFlags(level) {}
    122 
    123    constexpr HeaderFlags(NestedLevel level, PriorityValue priority,
    124                          MessageCompression compression, LazySend lazy_send,
    125                          Constructor constructor, Sync sync, Reply reply)
    126        : mFlags(level | (priority << 2) |
    127                 (compression == COMPRESSION_ENABLED ? COMPRESS_BIT
    128                  : compression == COMPRESSION_ALL   ? COMPRESSALL_BIT
    129                                                     : 0) |
    130                 (lazy_send == LAZY_SEND ? LAZY_SEND_BIT : 0) |
    131                 (constructor == CONSTRUCTOR ? CONSTRUCTOR_BIT : 0) |
    132                 (sync == SYNC ? SYNC_BIT : 0) |
    133                 (reply == REPLY ? REPLY_BIT : 0)) {}
    134 
    135    NestedLevel Level() const {
    136      return static_cast<NestedLevel>(mFlags & NESTED_MASK);
    137    }
    138 
    139    PriorityValue Priority() const {
    140      return static_cast<PriorityValue>((mFlags & PRIO_MASK) >> 2);
    141    }
    142 
    143    MessageCompression Compression() const {
    144      return ((mFlags & COMPRESS_BIT)      ? COMPRESSION_ENABLED
    145              : (mFlags & COMPRESSALL_BIT) ? COMPRESSION_ALL
    146                                           : COMPRESSION_NONE);
    147    }
    148 
    149    bool IsLazySend() const { return (mFlags & LAZY_SEND_BIT) != 0; }
    150 
    151    bool IsConstructor() const { return (mFlags & CONSTRUCTOR_BIT) != 0; }
    152    bool IsSync() const { return (mFlags & SYNC_BIT) != 0; }
    153    bool IsReply() const { return (mFlags & REPLY_BIT) != 0; }
    154 
    155    bool IsReplyError() const { return (mFlags & REPLY_ERROR_BIT) != 0; }
    156    bool IsRelay() const { return (mFlags & RELAY_BIT) != 0; }
    157 
    158   private:
    159    void SetConstructor() { mFlags |= CONSTRUCTOR_BIT; }
    160    void SetSync() { mFlags |= SYNC_BIT; }
    161    void SetReply() { mFlags |= REPLY_BIT; }
    162    void SetReplyError() { mFlags |= REPLY_ERROR_BIT; }
    163    void SetRelay(bool relay) {
    164      if (relay) {
    165        mFlags |= RELAY_BIT;
    166      } else {
    167        mFlags &= ~RELAY_BIT;
    168      }
    169    }
    170 
    171    uint32_t mFlags;
    172  };
    173 
    174  virtual ~Message();
    175 
    176  // Initialize a message with a user-defined type, priority value, and
    177  // destination WebView ID.
    178  Message(routeid_t routing_id, msgid_t type,
    179          uint32_t segment_capacity = 0,  // 0 for the default capacity.
    180          HeaderFlags flags = HeaderFlags());
    181 
    182  Message(const char* data, int data_len);
    183 
    184  Message(const Message&) = delete;
    185  Message(Message&&) = delete;
    186  Message& operator=(const Message&) = delete;
    187  Message& operator=(Message&&) = delete;
    188 
    189  // Helper method for the common case (default segmentCapacity, recording
    190  // the write latency of messages) of IPDL message creation.  This helps
    191  // move the malloc and some of the parameter setting out of autogenerated
    192  // code.
    193  static mozilla::UniquePtr<Message> IPDLMessage(routeid_t routing_id,
    194                                                 msgid_t type,
    195                                                 uint32_t segmentCapacity,
    196                                                 HeaderFlags flags);
    197 
    198  // One-off constructors for special error-handling messages.
    199  static mozilla::UniquePtr<Message> ForSyncDispatchError(NestedLevel level);
    200 
    201  NestedLevel nested_level() const { return header()->flags.Level(); }
    202 
    203  PriorityValue priority() const { return header()->flags.Priority(); }
    204 
    205  bool is_constructor() const { return header()->flags.IsConstructor(); }
    206 
    207  // True if this is a synchronous message.
    208  bool is_sync() const { return header()->flags.IsSync(); }
    209 
    210  MessageCompression compress_type() const {
    211    return header()->flags.Compression();
    212  }
    213 
    214  bool is_lazy_send() const { return header()->flags.IsLazySend(); }
    215 
    216  bool is_reply() const { return header()->flags.IsReply(); }
    217 
    218  bool is_reply_error() const { return header()->flags.IsReplyError(); }
    219 
    220  msgid_t type() const { return header()->type; }
    221 
    222  routeid_t routing_id() const { return header()->routing; }
    223 
    224  void set_routing_id(routeid_t new_id) { header()->routing = new_id; }
    225 
    226  seqno_t transaction_id() const { return header()->txid; }
    227 
    228  void set_transaction_id(seqno_t txid) { header()->txid = txid; }
    229 
    230  seqno_t seqno() const { return header()->seqno; }
    231 
    232  void set_seqno(seqno_t aSeqno) { header()->seqno = aSeqno; }
    233 
    234  const char* name() const { return StringFromIPCMessageType(type()); }
    235 
    236  bool has_any_attachments() const;
    237 
    238  uint32_t num_handles() const;
    239 
    240  bool is_relay() const { return header()->flags.IsRelay(); }
    241  void set_relay(bool new_relay) { header()->flags.SetRelay(new_relay); }
    242 
    243  template <class T>
    244  static bool Dispatch(const Message* msg, T* obj, void (T::*func)()) {
    245    (obj->*func)();
    246    return true;
    247  }
    248 
    249  template <class T>
    250  static bool Dispatch(const Message* msg, T* obj, void (T::*func)() const) {
    251    (obj->*func)();
    252    return true;
    253  }
    254 
    255  template <class T>
    256  static bool Dispatch(const Message* msg, T* obj,
    257                       void (T::*func)(const Message&)) {
    258    (obj->*func)(*msg);
    259    return true;
    260  }
    261 
    262  template <class T>
    263  static bool Dispatch(const Message* msg, T* obj,
    264                       void (T::*func)(const Message&) const) {
    265    (obj->*func)(*msg);
    266    return true;
    267  }
    268 
    269  // We should not be sending messages that are smaller than our header size.
    270  void AssertAsLargeAsHeader() const;
    271 
    272  // UserMessage implementation
    273  size_t GetSizeIfSerialized() const override { return size(); }
    274  bool WillBeRoutedExternally(mojo::core::ports::UserMessageEvent&) override;
    275 
    276  // Write the given footer bytes to the end of the current message. The
    277  // footer's `data_len` will be padded to a multiple of 4 bytes.
    278  void WriteFooter(const void* data, uint32_t data_len);
    279  // Read a footer written with `WriteFooter` from the end of the message, given
    280  // a buffer and the length of the footer. If `truncate` is true, the message
    281  // will be truncated, removing the footer.
    282  [[nodiscard]] bool ReadFooter(void* buffer, uint32_t buffer_len,
    283                                bool truncate);
    284 
    285  uint32_t event_footer_size() const { return header()->event_footer_size; }
    286 
    287  void set_event_footer_size(uint32_t size) {
    288    header()->event_footer_size = size;
    289  }
    290 
    291  static int HeaderSize() { return sizeof(Header); }
    292 
    293  // Figure out how big the message starting at range_start is. Returns 0 if
    294  // there's no enough data to determine (i.e., if [range_start, range_end) does
    295  // not contain enough of the message header to know the size).
    296  static uint32_t MessageSize(const char* range_start, const char* range_end) {
    297    return Pickle::MessageSize(HeaderSize(), range_start, range_end);
    298  }
    299 
    300  bool WriteFileHandle(mozilla::UniqueFileHandle handle);
    301 
    302  // WARNING: This method is marked as `const` so it can be called when
    303  // deserializing the message, but will mutate it, consuming the handle.
    304  bool ConsumeFileHandle(PickleIterator* iter,
    305                         mozilla::UniqueFileHandle* handle) const;
    306 
    307  // Called when receiving an IPC message to attach file handles which were
    308  // received from IPC. Must only be called when there are no handles on this
    309  // IPC::Message.
    310  void SetAttachedFileHandles(nsTArray<mozilla::UniqueFileHandle> handles);
    311 
    312 #if defined(XP_DARWIN)
    313  void set_fd_cookie(uint32_t cookie) { header()->cookie = cookie; }
    314  uint32_t fd_cookie() const { return header()->cookie; }
    315 #endif
    316 
    317  void WritePort(mozilla::ipc::ScopedPort port);
    318 
    319  // This method consumes the port from the message, preventing the message's
    320  // destructor from destroying the port and meaning that future attempts to
    321  // read this port will instead produce an invalid port.
    322  //
    323  // WARNING: This method is marked as `const` so it can be called when
    324  // deserializing the message, but will mutate the message.
    325  bool ConsumePort(PickleIterator* iter, mozilla::ipc::ScopedPort* port) const;
    326 
    327  // Called when loading an IPC message to attach ports which were recieved form
    328  // IPC. Must only be called when there are no ports on this IPC::Message.
    329  void SetAttachedPorts(nsTArray<mozilla::ipc::ScopedPort> ports);
    330 
    331 #if defined(XP_DARWIN)
    332  bool WriteMachSendRight(mozilla::UniqueMachSendRight port);
    333 
    334  // WARNING: This method is marked as `const` so it can be called when
    335  // deserializing the message, but will mutate it, consuming the send rights.
    336  bool ConsumeMachSendRight(PickleIterator* iter,
    337                            mozilla::UniqueMachSendRight* port) const;
    338 
    339  uint32_t num_send_rights() const;
    340 
    341  bool WriteMachReceiveRight(mozilla::UniqueMachReceiveRight port);
    342 
    343  // WARNING: This method is marked as `const` so it can be called when
    344  // deserializing the message, but will mutate it, consuming the send rights.
    345  bool ConsumeMachReceiveRight(PickleIterator* iter,
    346                               mozilla::UniqueMachReceiveRight* port) const;
    347 
    348  uint32_t num_receive_rights() const;
    349 #endif
    350 
    351 #ifdef FUZZING_SNAPSHOT
    352  bool IsFuzzMsg() const { return isFuzzMsg; }
    353  void SetFuzzMsg() { isFuzzMsg = true; }
    354 #endif
    355 
    356  void NoteLargeBufferShmemFailure(uint32_t size) {
    357    large_buffer_shmem_failure_size_ += size;
    358  }
    359  size_t LargeBufferShmemFailureSize() const {
    360    return large_buffer_shmem_failure_size_;
    361  }
    362 
    363  friend class Channel;
    364  friend class ChannelMach;
    365  friend class ChannelPosix;
    366  friend class ChannelWin;
    367  friend class MessageReplyDeserializer;
    368  friend class SyncMessage;
    369  friend class mozilla::ipc::MiniTransceiver;
    370 
    371 #if !defined(XP_DARWIN) && !defined(FUZZING_SNAPSHOT)
    372 protected:
    373 #endif
    374 
    375  struct Header : Pickle::Header {
    376    // Pickle::Header contains a 32-bit payload_size field
    377    msgid_t type;                // specifies the user-defined message type
    378    HeaderFlags flags;           // specifies control flags for the message
    379    uint32_t event_footer_size;  // Size of the message's event footer
    380 
    381    routeid_t routing;  // ID of the view that this message is destined for
    382    seqno_t txid;   // For sync messages, a transaction ID for message ordering.
    383    seqno_t seqno;  // Sequence number
    384 
    385    uint32_t num_handles;  // the number of handles included with this message
    386 #if defined(XP_DARWIN)
    387    uint32_t cookie;  // cookie to ACK that the descriptors have been read.
    388    uint32_t num_send_rights;  // the number of mach send rights included with
    389                               // this message
    390 #endif
    391    uint32_t _padding;
    392  };
    393  static_assert(std::has_unique_object_representations_v<Header>,
    394                "Header must not contain padding bytes");
    395 
    396  Header* header() { return headerT<Header>(); }
    397  const Header* header() const { return headerT<Header>(); }
    398 
    399  // The set of file handles which are attached to this message.
    400  //
    401  // Mutable, as this array can be mutated during `ReadHandle` when
    402  // deserializing a message.
    403  mutable nsTArray<mozilla::UniqueFileHandle> attached_handles_;
    404 
    405  // The set of mojo ports which are attached to this message.
    406  //
    407  // Mutable, as this array can be mutated during `ConsumePort` when
    408  // deserializing a message.
    409  mutable nsTArray<mozilla::ipc::ScopedPort> attached_ports_;
    410 
    411 #if defined(XP_DARWIN)
    412  // The set of mach send rights which are attached to this message.
    413  //
    414  // Mutable, as this array can be mutated during `ConsumeMachSendRight` when
    415  // deserializing a message.
    416  mutable nsTArray<mozilla::UniqueMachSendRight> attached_send_rights_;
    417 
    418  // The set of mach receive rights which are attached to this message.
    419  //
    420  // Mutable, as this array can be mutated during `ConsumeMachReceiveRight` when
    421  // deserializing a message.
    422  mutable nsTArray<mozilla::UniqueMachReceiveRight> attached_receive_rights_;
    423 
    424  // Mach voucher handle. This is kept alive to indicate that this Message is
    425  // being processed, which may be used by the system to temporarily boost the
    426  // QoS for this process.
    427  mozilla::UniqueMachSendRight mach_voucher_;
    428 #endif
    429 
    430  // Total size of buffers which should have been sent in shared memory, but had
    431  // to fall back to being sent inline due to shmem allocation or mapping
    432  // failures.
    433  uint32_t large_buffer_shmem_failure_size_ = 0;
    434 
    435 #ifdef FUZZING_SNAPSHOT
    436  bool isFuzzMsg = false;
    437 #endif
    438 };
    439 
    440 //------------------------------------------------------------------------------
    441 
    442 }  // namespace IPC
    443 
    444 enum SpecialRoutingIDs : IPC::Message::routeid_t {
    445  // indicates that we don't have a routing ID yet.
    446  MSG_ROUTING_NONE = INT64_MIN,
    447 
    448  // indicates a general message not sent to a particular tab.
    449  MSG_ROUTING_CONTROL = INT64_MAX
    450 };
    451 
    452 #endif  // CHROME_COMMON_IPC_MESSAGE_H__