capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

arena.h (20598B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #pragma once
     23 
     24 #ifndef CAPNP_PRIVATE
     25 #error "This header is only meant to be included by Cap'n Proto's own source code."
     26 #endif
     27 
     28 #include <kj/common.h>
     29 #include <kj/mutex.h>
     30 #include <kj/exception.h>
     31 #include <kj/vector.h>
     32 #include <kj/units.h>
     33 #include "common.h"
     34 #include "message.h"
     35 #include "layout.h"
     36 #include <kj/map.h>
     37 
     38 #if !CAPNP_LITE
     39 #include "capability.h"
     40 #endif  // !CAPNP_LITE
     41 
     42 CAPNP_BEGIN_HEADER
     43 
     44 namespace capnp {
     45 
     46 #if !CAPNP_LITE
     47 class ClientHook;
     48 #endif  // !CAPNP_LITE
     49 
     50 namespace _ {  // private
     51 
     52 class SegmentReader;
     53 class SegmentBuilder;
     54 class Arena;
     55 class BuilderArena;
     56 class ReadLimiter;
     57 
     58 class Segment;
     59 typedef kj::Id<uint32_t, Segment> SegmentId;
     60 
     61 class ReadLimiter {
     62   // Used to keep track of how much data has been processed from a message, and cut off further
     63   // processing if and when a particular limit is reached.  This is primarily intended to guard
     64   // against maliciously-crafted messages which contain cycles or overlapping structures.  Cycles
     65   // and overlapping are not permitted by the Cap'n Proto format because in many cases they could
     66   // be used to craft a deceptively small message which could consume excessive server resources to
     67   // process, perhaps even sending it into an infinite loop.  Actually detecting overlaps would be
     68   // time-consuming, so instead we just keep track of how many words worth of data structures the
     69   // receiver has actually dereferenced and error out if this gets too high.
     70   //
     71   // This counting takes place as you call getters (for non-primitive values) on the message
     72   // readers.  If you call the same getter twice, the data it returns may be double-counted.  This
     73   // should not be a big deal in most cases -- just set the read limit high enough that it will
     74   // only trigger in unreasonable cases.
     75   //
     76   // This class is "safe" to use from multiple threads for its intended use case.  Threads may
     77   // overwrite each others' changes to the counter, but this is OK because it only means that the
     78   // limit is enforced a bit less strictly -- it will still kick in eventually.
     79 
     80 public:
     81   inline explicit ReadLimiter();                     // No limit.
     82   inline explicit ReadLimiter(WordCount64 limit);    // Limit to the given number of words.
     83 
     84   inline void reset(WordCount64 limit);
     85 
     86   KJ_ALWAYS_INLINE(bool canRead(WordCount64 amount, Arena* arena));
     87 
     88   void unread(WordCount64 amount);
     89   // Adds back some words to the limit.  Useful when the caller knows they are double-reading
     90   // some data.
     91 
     92 private:
     93   alignas(8) volatile uint64_t limit;
     94   // Current limit, decremented each time catRead() is called. We modify this variable using atomics
     95   // with "relaxed" thread safety to make TSAN happy (on ARM & x86 this is no different from a
     96   // regular read/write of the variable). See the class comment for why this is OK (previously we
     97   // used a regular volatile variable - this is just to make ASAN happy).
     98   //
     99   // alignas(8) is the default on 64-bit systems, but needed on 32-bit to avoid an expensive
    100   // unaligned atomic operation.
    101 
    102   KJ_DISALLOW_COPY(ReadLimiter);
    103 
    104   KJ_ALWAYS_INLINE(void setLimit(uint64_t newLimit)) {
    105 #if defined(__GNUC__) || defined(__clang__)
    106     __atomic_store_n(&limit, newLimit, __ATOMIC_RELAXED);
    107 #else
    108     limit = newLimit;
    109 #endif
    110   }
    111 
    112   KJ_ALWAYS_INLINE(uint64_t readLimit() const) {
    113 #if defined(__GNUC__) || defined(__clang__)
    114     return __atomic_load_n(&limit, __ATOMIC_RELAXED);
    115 #else
    116     return limit;
    117 #endif
    118   }
    119 };
    120 
    121 #if !CAPNP_LITE
    122 class BrokenCapFactory {
    123   // Callback for constructing broken caps.  We use this so that we can avoid arena.c++ having a
    124   // link-time dependency on capability code that lives in libcapnp-rpc.
    125 
    126 public:
    127   virtual kj::Own<ClientHook> newBrokenCap(kj::StringPtr description) = 0;
    128   virtual kj::Own<ClientHook> newNullCap() = 0;
    129 };
    130 #endif  // !CAPNP_LITE
    131 
    132 class SegmentReader {
    133 public:
    134   inline SegmentReader(Arena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
    135                        ReadLimiter* readLimiter);
    136 
    137   KJ_ALWAYS_INLINE(const word* checkOffset(const word* from, ptrdiff_t offset));
    138   // Adds the given offset to the given pointer, checks that it is still within the bounds of the
    139   // segment, then returns it. Note that the "end" pointer of the segment (which technically points
    140   // to the word after the last in the segment) is considered in-bounds for this purpose, so you
    141   // can't necessarily dereference it. You must call checkObject() next to check that the object
    142   // you want to read is entirely in-bounds.
    143   //
    144   // If `from + offset` is out-of-range, this returns a pointer to the end of the segment. Thus,
    145   // any non-zero-sized object will fail `checkObject()`. We do this instead of throwing to save
    146   // some code footprint.
    147 
    148   KJ_ALWAYS_INLINE(bool checkObject(const word* start, WordCountN<31> size));
    149   // Assuming that `start` is in-bounds for this segment (probably checked using `checkOffset()`),
    150   // check that `start + size` is also in-bounds, and hence the whole area in-between is valid.
    151 
    152   KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount));
    153   // Indicates that the reader should pretend that `virtualAmount` additional data was read even
    154   // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer
    155   // where the element sizes are zero -- the sender could set the list size arbitrarily high and
    156   // cause the receiver to iterate over this list even though the message itself is small, so we
    157   // need to defend against DoS attacks based on this.
    158 
    159   inline Arena* getArena();
    160   inline SegmentId getSegmentId();
    161 
    162   inline const word* getStartPtr();
    163   inline SegmentWordCount getOffsetTo(const word* ptr);
    164   inline SegmentWordCount getSize();
    165 
    166   inline kj::ArrayPtr<const word> getArray();
    167 
    168   inline void unread(WordCount64 amount);
    169   // Add back some words to the ReadLimiter.
    170 
    171 private:
    172   Arena* arena;
    173   SegmentId id;
    174   kj::ArrayPtr<const word> ptr;  // size guaranteed to fit in SEGMENT_WORD_COUNT_BITS bits
    175   ReadLimiter* readLimiter;
    176 
    177   KJ_DISALLOW_COPY(SegmentReader);
    178 
    179   friend class SegmentBuilder;
    180 
    181   [[noreturn]] static void abortCheckObjectFault();
    182   // Called in debug mode in cases that would segfault in opt mode. (Should be impossible!)
    183 };
    184 
    185 class SegmentBuilder: public SegmentReader {
    186 public:
    187   inline SegmentBuilder(BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size,
    188                         ReadLimiter* readLimiter, SegmentWordCount wordsUsed = ZERO * WORDS);
    189   inline SegmentBuilder(BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
    190                         ReadLimiter* readLimiter);
    191   inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr),
    192                         ReadLimiter* readLimiter);
    193 
    194   KJ_ALWAYS_INLINE(word* allocate(SegmentWordCount amount));
    195 
    196   KJ_ALWAYS_INLINE(void checkWritable());
    197   // Throw an exception if the segment is read-only (meaning it is a reference to external data).
    198 
    199   KJ_ALWAYS_INLINE(word* getPtrUnchecked(SegmentWordCount offset));
    200   // Get a writable pointer into the segment.  Throws an exception if the segment is read-only (i.e.
    201   // a reference to external immutable data).
    202 
    203   inline BuilderArena* getArena();
    204 
    205   inline kj::ArrayPtr<const word> currentlyAllocated();
    206 
    207   inline void reset();
    208 
    209   inline bool isWritable() { return !readOnly; }
    210 
    211   inline void tryTruncate(word* from, word* to);
    212   // If `from` points just past the current end of the segment, then move the end back to `to`.
    213   // Otherwise, do nothing.
    214 
    215   inline bool tryExtend(word* from, word* to);
    216   // If `from` points just past the current end of the segment, and `to` is within the segment
    217   // boundaries, then move the end up to `to` and return true. Otherwise, do nothing and return
    218   // false.
    219 
    220 private:
    221   word* pos;
    222   // Pointer to a pointer to the current end point of the segment, i.e. the location where the
    223   // next object should be allocated.
    224 
    225   bool readOnly;
    226 
    227   [[noreturn]] void throwNotWritable();
    228 
    229   KJ_DISALLOW_COPY(SegmentBuilder);
    230 };
    231 
    232 class Arena {
    233 public:
    234   virtual ~Arena() noexcept(false);
    235 
    236   virtual SegmentReader* tryGetSegment(SegmentId id) = 0;
    237   // Gets the segment with the given ID, or return nullptr if no such segment exists.
    238 
    239   virtual void reportReadLimitReached() = 0;
    240   // Called to report that the read limit has been reached.  See ReadLimiter, below.  This invokes
    241   // the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller
    242   // will need to continue with default values.
    243 };
    244 
    245 class ReaderArena final: public Arena {
    246 public:
    247   explicit ReaderArena(MessageReader* message);
    248   ~ReaderArena() noexcept(false);
    249   KJ_DISALLOW_COPY(ReaderArena);
    250 
    251   size_t sizeInWords();
    252 
    253   // implements Arena ------------------------------------------------
    254   SegmentReader* tryGetSegment(SegmentId id) override;
    255   void reportReadLimitReached() override;
    256 
    257 private:
    258   MessageReader* message;
    259   ReadLimiter readLimiter;
    260 
    261   // Optimize for single-segment messages so that small messages are handled quickly.
    262   SegmentReader segment0;
    263 
    264   typedef kj::HashMap<uint, kj::Own<SegmentReader>> SegmentMap;
    265   kj::MutexGuarded<kj::Maybe<SegmentMap>> moreSegments;
    266   // We need to mutex-guard the segment map because we lazily initialize segments when they are
    267   // first requested, but a Reader is allowed to be used concurrently in multiple threads.  Luckily
    268   // this only applies to large messages.
    269   //
    270   // TODO(perf):  Thread-local thing instead?  Some kind of lockless map?  Or do sharing of data
    271   //   in a different way, where you have to construct a new MessageReader in each thread (but
    272   //   possibly backed by the same data)?
    273 
    274   ReaderArena(MessageReader* message, kj::ArrayPtr<const word> firstSegment);
    275   ReaderArena(MessageReader* message, const word* firstSegment, SegmentWordCount firstSegmentSize);
    276 };
    277 
    278 class BuilderArena final: public Arena {
    279   // A BuilderArena that does not allow the injection of capabilities.
    280 
    281 public:
    282   explicit BuilderArena(MessageBuilder* message);
    283   BuilderArena(MessageBuilder* message, kj::ArrayPtr<MessageBuilder::SegmentInit> segments);
    284   ~BuilderArena() noexcept(false);
    285   KJ_DISALLOW_COPY(BuilderArena);
    286 
    287   size_t sizeInWords();
    288 
    289   inline SegmentBuilder* getRootSegment() { return &segment0; }
    290 
    291   kj::ArrayPtr<const kj::ArrayPtr<const word>> getSegmentsForOutput();
    292   // Get an array of all the segments, suitable for writing out.  This only returns the allocated
    293   // portion of each segment, whereas tryGetSegment() returns something that includes
    294   // not-yet-allocated space.
    295 
    296   inline CapTableBuilder* getLocalCapTable() {
    297     // Return a CapTableBuilder that merely implements local loopback. That is, you can set
    298     // capabilities, then read the same capabilities back, but there is no intent ever to transmit
    299     // these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this
    300     // by default.
    301     //
    302     // TODO(cleanup): It's sort of a hack that this exists. In theory, perhaps, unimbued
    303     //   MessageBuilders should throw exceptions on any attempt to access capability fields, like
    304     //   unimbued MessageReaders do. However, lots of code exists which uses MallocMessageBuilder
    305     //   as a temporary holder for data to be copied in and out (without being serialized), and it
    306     //   is expected that such data can include capabilities, which is admittedly reasonable.
    307     //   Therefore, all MessageBuilders must have a cap table by default. Arguably we should
    308     //   deprecate this usage and instead define a new helper type for this exact purpose.
    309 
    310     return &localCapTable;
    311   }
    312 
    313   kj::Own<_::CapTableBuilder> releaseLocalCapTable() {
    314     return kj::heap<LocalCapTable>(kj::mv(localCapTable));
    315   }
    316 
    317   SegmentBuilder* getSegment(SegmentId id);
    318   // Get the segment with the given id.  Crashes or throws an exception if no such segment exists.
    319 
    320   struct AllocateResult {
    321     SegmentBuilder* segment;
    322     word* words;
    323   };
    324 
    325   AllocateResult allocate(SegmentWordCount amount);
    326   // Find a segment with at least the given amount of space available and allocate the space.
    327   // Note that allocating directly from a particular segment is much faster, but allocating from
    328   // the arena is guaranteed to succeed.  Therefore callers should try to allocate from a specific
    329   // segment first if there is one, then fall back to the arena.
    330 
    331   SegmentBuilder* addExternalSegment(kj::ArrayPtr<const word> content);
    332   // Add a new segment to the arena which points to some existing memory region.  The segment is
    333   // assumed to be completley full; the arena will never allocate from it.  In fact, the segment
    334   // is considered read-only.  Any attempt to get a Builder pointing into this segment will throw
    335   // an exception.  Readers are allowed, however.
    336   //
    337   // This can be used to inject some external data into a message without a copy, e.g. embedding a
    338   // large mmap'd file into a message as `Data` without forcing that data to actually be read in
    339   // from disk (until the message itself is written out).  `Orphanage` provides the public API for
    340   // this feature.
    341 
    342   // implements Arena ------------------------------------------------
    343   SegmentReader* tryGetSegment(SegmentId id) override;
    344   void reportReadLimitReached() override;
    345 
    346 private:
    347   MessageBuilder* message;
    348   ReadLimiter dummyLimiter;
    349 
    350   class LocalCapTable final: public CapTableBuilder {
    351   public:
    352     kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override;
    353     uint injectCap(kj::Own<ClientHook>&& cap) override;
    354     void dropCap(uint index) override;
    355 
    356 #if !CAPNP_LITE
    357   private:
    358     kj::Vector<kj::Maybe<kj::Own<ClientHook>>> capTable;
    359 #endif // ! CAPNP_LITE
    360   };
    361 
    362   LocalCapTable localCapTable;
    363 
    364   SegmentBuilder segment0;
    365   kj::ArrayPtr<const word> segment0ForOutput;
    366 
    367   struct MultiSegmentState {
    368     kj::Vector<kj::Own<SegmentBuilder>> builders;
    369     kj::Vector<kj::ArrayPtr<const word>> forOutput;
    370   };
    371   kj::Maybe<kj::Own<MultiSegmentState>> moreSegments;
    372 
    373   SegmentBuilder* segmentWithSpace = nullptr;
    374   // When allocating, look for space in this segment first before resorting to allocating a new
    375   // segment.  This is not necessarily the last segment because addExternalSegment() may add a
    376   // segment that is already-full, in which case we don't update this pointer.
    377 
    378   template <typename T>  // Can be `word` or `const word`.
    379   SegmentBuilder* addSegmentInternal(kj::ArrayPtr<T> content);
    380 };
    381 
    382 // =======================================================================================
    383 
    384 inline ReadLimiter::ReadLimiter()
    385     : limit(kj::maxValue) {}
    386 
    387 inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(unbound(limit / WORDS)) {}
    388 
    389 inline void ReadLimiter::reset(WordCount64 limit) {
    390   setLimit(unbound(limit / WORDS));
    391 }
    392 
    393 inline bool ReadLimiter::canRead(WordCount64 amount, Arena* arena) {
    394   // Be careful not to store an underflowed value into `limit`, even if multiple threads are
    395   // decrementing it.
    396   uint64_t current = readLimit();
    397   if (KJ_UNLIKELY(unbound(amount / WORDS) > current)) {
    398     arena->reportReadLimitReached();
    399     return false;
    400   } else {
    401     setLimit(current - unbound(amount / WORDS));
    402     return true;
    403   }
    404 }
    405 
    406 // -------------------------------------------------------------------
    407 
    408 inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, const word* ptr,
    409                                     SegmentWordCount size, ReadLimiter* readLimiter)
    410     : arena(arena), id(id), ptr(kj::arrayPtr(ptr, unbound(size / WORDS))),
    411       readLimiter(readLimiter) {}
    412 
    413 inline const word* SegmentReader::checkOffset(const word* from, ptrdiff_t offset) {
    414   ptrdiff_t min = ptr.begin() - from;
    415   ptrdiff_t max = ptr.end() - from;
    416   if (offset >= min && offset <= max) {
    417     return from + offset;
    418   } else {
    419     return ptr.end();
    420   }
    421 }
    422 
    423 inline bool SegmentReader::checkObject(const word* start, WordCountN<31> size) {
    424   auto startOffset = intervalLength(ptr.begin(), start, MAX_SEGMENT_WORDS);
    425 #ifdef KJ_DEBUG
    426   if (startOffset > bounded(ptr.size()) * WORDS) {
    427     abortCheckObjectFault();
    428   }
    429 #endif
    430   return startOffset + size <= bounded(ptr.size()) * WORDS &&
    431       readLimiter->canRead(size, arena);
    432 }
    433 
    434 inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) {
    435   return readLimiter->canRead(virtualAmount, arena);
    436 }
    437 
    438 inline Arena* SegmentReader::getArena() { return arena; }
    439 inline SegmentId SegmentReader::getSegmentId() { return id; }
    440 inline const word* SegmentReader::getStartPtr() { return ptr.begin(); }
    441 inline SegmentWordCount SegmentReader::getOffsetTo(const word* ptr) {
    442   KJ_IREQUIRE(this->ptr.begin() <= ptr && ptr <= this->ptr.end());
    443   return intervalLength(this->ptr.begin(), ptr, MAX_SEGMENT_WORDS);
    444 }
    445 inline SegmentWordCount SegmentReader::getSize() {
    446   return assumeBits<SEGMENT_WORD_COUNT_BITS>(ptr.size()) * WORDS;
    447 }
    448 inline kj::ArrayPtr<const word> SegmentReader::getArray() { return ptr; }
    449 inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); }
    450 
    451 // -------------------------------------------------------------------
    452 
    453 inline SegmentBuilder::SegmentBuilder(
    454     BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size,
    455     ReadLimiter* readLimiter, SegmentWordCount wordsUsed)
    456     : SegmentReader(arena, id, ptr, size, readLimiter),
    457       pos(ptr + wordsUsed), readOnly(false) {}
    458 inline SegmentBuilder::SegmentBuilder(
    459     BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
    460     ReadLimiter* readLimiter)
    461     : SegmentReader(arena, id, ptr, size, readLimiter),
    462       // const_cast is safe here because the member won't ever be dereferenced because it appears
    463       // to point to the end of the segment anyway.
    464       pos(const_cast<word*>(ptr + size)), readOnly(true) {}
    465 inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr),
    466                                       ReadLimiter* readLimiter)
    467     : SegmentReader(arena, id, nullptr, ZERO * WORDS, readLimiter),
    468       pos(nullptr), readOnly(false) {}
    469 
    470 inline word* SegmentBuilder::allocate(SegmentWordCount amount) {
    471   if (intervalLength(pos, ptr.end(), MAX_SEGMENT_WORDS) < amount) {
    472     // Not enough space in the segment for this allocation.
    473     return nullptr;
    474   } else {
    475     // Success.
    476     word* result = pos;
    477     pos = pos + amount;
    478     return result;
    479   }
    480 }
    481 
    482 inline void SegmentBuilder::checkWritable() {
    483   if (KJ_UNLIKELY(readOnly)) throwNotWritable();
    484 }
    485 
    486 inline word* SegmentBuilder::getPtrUnchecked(SegmentWordCount offset) {
    487   return const_cast<word*>(ptr.begin() + offset);
    488 }
    489 
    490 inline BuilderArena* SegmentBuilder::getArena() {
    491   // Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base
    492   // class with an Arena pointer that actually points to a BuilderArena.
    493   return static_cast<BuilderArena*>(arena);
    494 }
    495 
    496 inline kj::ArrayPtr<const word> SegmentBuilder::currentlyAllocated() {
    497   return kj::arrayPtr(ptr.begin(), pos - ptr.begin());
    498 }
    499 
    500 inline void SegmentBuilder::reset() {
    501   word* start = getPtrUnchecked(ZERO * WORDS);
    502   memset(start, 0, (pos - start) * sizeof(word));
    503   pos = start;
    504 }
    505 
    506 inline void SegmentBuilder::tryTruncate(word* from, word* to) {
    507   if (pos == from) pos = to;
    508 }
    509 
    510 inline bool SegmentBuilder::tryExtend(word* from, word* to) {
    511   // Careful about overflow.
    512   if (pos == from && to <= ptr.end() && to >= from) {
    513     pos = to;
    514     return true;
    515   } else {
    516     return false;
    517   }
    518 }
    519 
    520 }  // namespace _ (private)
    521 }  // namespace capnp
    522 
    523 CAPNP_END_HEADER