Home | History | Annotate | Download | only in system
      1 // Copyright 2014 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 #ifndef MOJO_SYSTEM_TRANSPORT_DATA_H_
      6 #define MOJO_SYSTEM_TRANSPORT_DATA_H_
      7 
      8 #include <stdint.h>
      9 
     10 #include <vector>
     11 
     12 #include "base/macros.h"
     13 #include "base/memory/aligned_memory.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "build/build_config.h"
     16 #include "mojo/embedder/platform_handle.h"
     17 #include "mojo/embedder/platform_handle_vector.h"
     18 #include "mojo/system/dispatcher.h"
     19 #include "mojo/system/system_impl_export.h"
     20 
     21 namespace mojo {
     22 namespace system {
     23 
     24 class Channel;
     25 
     26 // This class is used by |MessageInTransit| to represent handles (|Dispatcher|s)
     27 // in various stages of serialization.
     28 //
     29 // The stages are:
     30 //   - Before reaching |TransportData|: Turn |DispatcherTransport|s into
     31 //     |Dispatcher|s that are "owned" by (and attached to) a |MessageInTransit|.
     32 //     This invalidates the handles in the space of the sending application
     33 //     (and, e.g., if another thread is waiting on such a handle, it'll be
     34 //     notified of this invalidation).
     35 //   - Serialize these dispatchers into the |TransportData|: First, for each
     36 //     attached dispatcher, there's an entry in the |TransportData|'s "handle
     37 //     table", which points to a segment of (dispatcher-type-dependent) data.
     38 //   - During the serialization of the dispatchers, |PlatformHandle|s may be
     39 //     detached from the dispatchers and attached to the |TransportData|.
     40 //   - Before sending the |MessageInTransit|, including its main buffer and the
     41 //     |TransportData|'s buffer, the |Channel| sends any |PlatformHandle|s (in a
     42 //     platform-, and possibly sandbox-situation-, specific way) first. In doing
     43 //     so, it appends a "platform handle table" to the |TransportData|
     44 //     containing information about how to deserialize these |PlatformHandle|s.
     45 //   - Finally, at this point, to send the |MessageInTransit|, there only
     46 //     remains "inert" data: the |MessageInTransit|'s main buffer and data from
     47 //     the |TransportData|, consisting of the "handle table" (one entry for each
     48 //     attached dispatcher), dispatcher-type-specific data (one segment for each
     49 //     entry in the "handle table"), and the "platform handle table" (one entry
     50 //     for each attached |PlatformHandle|).
     51 //
     52 // To receive a message (|MessageInTransit|), the "reverse" happens:
     53 //   - On POSIX, receive and buffer |PlatformHandle|s (i.e., FDs), which were
     54 //     sent before the "inert" data.
     55 //   - Receive the "inert" data from the |MessageInTransit|. Examine its
     56 //     "platform handle table". On POSIX, match its entries with the buffered
     57 //     |PlatformHandle|s, which were previously received. On Windows, do what's
     58 //     necessary to obtain |PlatformHandle|s (e.g.: i. if the sender is fully
     59 //     trusted and able to duplicate handle into the receiver, then just pick
     60 //     out the |HANDLE| value; ii. if the receiver is fully trusted and able to
     61 //     duplicate handles from the receiver, do the |DuplicateHandle()|; iii.
     62 //     otherwise, talk to a broker to get handles). Reattach all the
     63 //     |PlatformHandle|s to the |MessageInTransit|.
     64 //   - For each entry in the "handle table", use serialized dispatcher data to
     65 //     reconstitute a dispatcher, taking ownership of associated
     66 //     |PlatformHandle|s (and detaching them). Attach these dispatchers to the
     67 //     |MessageInTransit|.
     68 //   - At this point, the |MessageInTransit| consists of its main buffer
     69 //     (primarily the data payload) and the attached dispatchers; the
     70 //     |TransportData| can be discarded.
     71 //   - When |MojoReadMessage()| is to give data to the application, attach the
     72 //     dispatchers to the (global, "core") handle table, getting handles; give
     73 //     the application the data payload and these handles.
     74 //
     75 // TODO(vtl): Everything above involving |PlatformHandle|s.
     76 class MOJO_SYSTEM_IMPL_EXPORT TransportData {
     77  public:
     78   // The maximum size of a single serialized dispatcher. This must be a multiple
     79   // of |kMessageAlignment|.
     80   static const size_t kMaxSerializedDispatcherSize = 10000;
     81 
     82   // The maximum number of platform handles to attach for a single serialized
     83   // dispatcher.
     84   static const size_t kMaxSerializedDispatcherPlatformHandles = 2;
     85 
     86   // The maximum possible size of a valid transport data buffer.
     87   static const size_t kMaxBufferSize;
     88 
     89   // The maximum total number of platform handles that may be attached.
     90   static const size_t kMaxPlatformHandles;
     91 
     92   TransportData(scoped_ptr<DispatcherVector> dispatchers, Channel* channel);
     93 
     94 #if defined(OS_POSIX)
     95   // This is a hacky POSIX-only constructor to directly attach only platform
     96   // handles to a message, used by |RawChannelPosix| to split messages with too
     97   // many platform handles into multiple messages. |Header| will be present, but
     98   // be zero. (No other information will be attached, and
     99   // |RawChannel::GetSerializedPlatformHandleSize()| should return zero.)
    100   explicit TransportData(
    101       embedder::ScopedPlatformHandleVectorPtr platform_handles);
    102 #endif
    103 
    104   ~TransportData();
    105 
    106   const void* buffer() const { return buffer_.get(); }
    107   void* buffer() { return buffer_.get(); }
    108   size_t buffer_size() const { return buffer_size_; }
    109 
    110   uint32_t platform_handle_table_offset() const {
    111     return header()->platform_handle_table_offset;
    112   }
    113 
    114   // Gets attached platform-specific handles; this may return null if there are
    115   // none. Note that the caller may mutate the set of platform-specific handles.
    116   const embedder::PlatformHandleVector* platform_handles() const {
    117     return platform_handles_.get();
    118   }
    119   embedder::PlatformHandleVector* platform_handles() {
    120     return platform_handles_.get();
    121   }
    122 
    123   // Receive-side functions:
    124 
    125   // Checks if the given buffer (from the "wire") looks like a valid
    126   // |TransportData| buffer. (Should only be called if |buffer_size| is
    127   // nonzero.) Returns null if valid, and a pointer to a human-readable error
    128   // message (for debug/logging purposes) on error. Note: This checks the
    129   // validity of the handle table entries (i.e., does range checking), but does
    130   // not check that the validity of the actual serialized dispatcher
    131   // information.
    132   static const char* ValidateBuffer(size_t serialized_platform_handle_size,
    133                                     const void* buffer,
    134                                     size_t buffer_size);
    135 
    136   // Gets the platform handle table from a (valid) |TransportData| buffer (which
    137   // should have been validated using |ValidateBuffer()| first).
    138   static void GetPlatformHandleTable(const void* transport_data_buffer,
    139                                      size_t* num_platform_handles,
    140                                      const void** platform_handle_table);
    141 
    142   // Deserializes dispatchers from the given (serialized) transport data buffer
    143   // (typically from a |MessageInTransit::View|) and vector of platform handles.
    144   // |buffer| should be non-null and |buffer_size| should be nonzero.
    145   static scoped_ptr<DispatcherVector> DeserializeDispatchers(
    146       const void* buffer,
    147       size_t buffer_size,
    148       embedder::ScopedPlatformHandleVectorPtr platform_handles,
    149       Channel* channel);
    150 
    151  private:
    152   // To allow us to make compile-assertions about |Header|, etc. in the .cc
    153   // file.
    154   struct PrivateStructForCompileAsserts;
    155 
    156   // Header for the "secondary buffer"/"transport data". Must be a multiple of
    157   // |MessageInTransit::kMessageAlignment| in size. Must be POD.
    158   struct Header {
    159     uint32_t num_handles;
    160     // TODO(vtl): Not used yet:
    161     uint32_t platform_handle_table_offset;
    162     uint32_t num_platform_handles;
    163     uint32_t unused;
    164   };
    165 
    166   struct HandleTableEntry {
    167     int32_t type;     // From |Dispatcher::Type| (|kTypeUnknown| for "invalid").
    168     uint32_t offset;  // Relative to the start of the "secondary buffer".
    169     uint32_t size;    // (Not including any padding.)
    170     uint32_t unused;
    171   };
    172 
    173   const Header* header() const {
    174     return reinterpret_cast<const Header*>(buffer_.get());
    175   }
    176 
    177   size_t buffer_size_;
    178   scoped_ptr<char, base::AlignedFreeDeleter> buffer_;  // Never null.
    179 
    180   // Any platform-specific handles attached to this message (for inter-process
    181   // transport). The vector (if any) owns the handles that it contains (and is
    182   // responsible for closing them).
    183   // TODO(vtl): With C++11, change it to a vector of |ScopedPlatformHandles|.
    184   embedder::ScopedPlatformHandleVectorPtr platform_handles_;
    185 
    186   DISALLOW_COPY_AND_ASSIGN(TransportData);
    187 };
    188 
    189 }  // namespace system
    190 }  // namespace mojo
    191 
    192 #endif  // MOJO_SYSTEM_TRANSPORT_DATA_H_
    193