Home | History | Annotate | Download | only in lib
      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_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_CONTEXT_H_
      6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_CONTEXT_H_
      7 
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include "base/compiler_specific.h"
     12 #include "base/component_export.h"
     13 #include "base/macros.h"
     14 #include "base/strings/string_piece.h"
     15 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
     16 
     17 static const int kMaxRecursionDepth = 100;
     18 
     19 namespace mojo {
     20 
     21 class Message;
     22 
     23 namespace internal {
     24 
     25 // ValidationContext is used when validating object sizes, pointers and handle
     26 // indices in the payload of incoming messages.
     27 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ValidationContext {
     28  public:
     29   // [data, data + data_num_bytes) specifies the initial valid memory range.
     30   // [0, num_handles) specifies the initial valid range of handle indices.
     31   // [0, num_associated_endpoint_handles) specifies the initial valid range of
     32   // associated endpoint handle indices.
     33   //
     34   // If provided, |message| and |description| provide additional information
     35   // to use when reporting validation errors. In addition if |message| is
     36   // provided, the MojoNotifyBadMessage API will be used to notify the system of
     37   // such errors.
     38   ValidationContext(const void* data,
     39                     size_t data_num_bytes,
     40                     size_t num_handles,
     41                     size_t num_associated_endpoint_handles,
     42                     Message* message = nullptr,
     43                     const base::StringPiece& description = "",
     44                     int stack_depth = 0);
     45 
     46   ~ValidationContext();
     47 
     48   // Claims the specified memory range.
     49   // The method succeeds if the range is valid to claim. (Please see
     50   // the comments for IsValidRange().)
     51   // On success, the valid memory range is shrinked to begin right after the end
     52   // of the claimed range.
     53   bool ClaimMemory(const void* position, uint32_t num_bytes) {
     54     uintptr_t begin = reinterpret_cast<uintptr_t>(position);
     55     uintptr_t end = begin + num_bytes;
     56 
     57     if (!InternalIsValidRange(begin, end))
     58       return false;
     59 
     60     data_begin_ = end;
     61     return true;
     62   }
     63 
     64   // Claims the specified encoded handle (which is basically a handle index).
     65   // The method succeeds if:
     66   // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|.
     67   // - the handle is contained inside the valid range of handle indices. In this
     68   // case, the valid range is shinked to begin right after the claimed handle.
     69   bool ClaimHandle(const Handle_Data& encoded_handle) {
     70     uint32_t index = encoded_handle.value;
     71     if (index == kEncodedInvalidHandleValue)
     72       return true;
     73 
     74     if (index < handle_begin_ || index >= handle_end_)
     75       return false;
     76 
     77     // |index| + 1 shouldn't overflow, because |index| is not the max value of
     78     // uint32_t (it is less than |handle_end_|).
     79     handle_begin_ = index + 1;
     80     return true;
     81   }
     82 
     83   // Claims the specified encoded associated endpoint handle.
     84   // The method succeeds if:
     85   // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|.
     86   // - the handle is contained inside the valid range of associated endpoint
     87   //   handle indices. In this case, the valid range is shinked to begin right
     88   //   after the claimed handle.
     89   bool ClaimAssociatedEndpointHandle(
     90       const AssociatedEndpointHandle_Data& encoded_handle) {
     91     uint32_t index = encoded_handle.value;
     92     if (index == kEncodedInvalidHandleValue)
     93       return true;
     94 
     95     if (index < associated_endpoint_handle_begin_ ||
     96         index >= associated_endpoint_handle_end_)
     97       return false;
     98 
     99     // |index| + 1 shouldn't overflow, because |index| is not the max value of
    100     // uint32_t (it is less than |associated_endpoint_handle_end_|).
    101     associated_endpoint_handle_begin_ = index + 1;
    102     return true;
    103   }
    104 
    105   // Returns true if the specified range is not empty, and the range is
    106   // contained inside the valid memory range.
    107   bool IsValidRange(const void* position, uint32_t num_bytes) const {
    108     uintptr_t begin = reinterpret_cast<uintptr_t>(position);
    109     uintptr_t end = begin + num_bytes;
    110 
    111     return InternalIsValidRange(begin, end);
    112   }
    113 
    114   // This object should be created on the stack once every time we recurse down
    115   // into a subfield during validation to make sure we don't recurse too deep
    116   // and blow the stack.
    117   class ScopedDepthTracker {
    118    public:
    119     // |ctx| must outlive this object.
    120     explicit ScopedDepthTracker(ValidationContext* ctx) : ctx_(ctx) {
    121       ++ctx_->stack_depth_;
    122     }
    123 
    124     ~ScopedDepthTracker() { --ctx_->stack_depth_; }
    125 
    126    private:
    127     ValidationContext* ctx_;
    128 
    129     DISALLOW_COPY_AND_ASSIGN(ScopedDepthTracker);
    130   };
    131 
    132   // Returns true if the recursion depth limit has been reached.
    133   bool ExceedsMaxDepth() WARN_UNUSED_RESULT {
    134     return stack_depth_ > kMaxRecursionDepth;
    135   }
    136 
    137   Message* message() const { return message_; }
    138   const base::StringPiece& description() const { return description_; }
    139 
    140  private:
    141   bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const {
    142     return end > begin && begin >= data_begin_ && end <= data_end_;
    143   }
    144 
    145   Message* const message_;
    146   const base::StringPiece description_;
    147 
    148   // [data_begin_, data_end_) is the valid memory range.
    149   uintptr_t data_begin_;
    150   uintptr_t data_end_;
    151 
    152   // [handle_begin_, handle_end_) is the valid handle index range.
    153   uint32_t handle_begin_;
    154   uint32_t handle_end_;
    155 
    156   // [associated_endpoint_handle_begin_, associated_endpoint_handle_end_) is the
    157   // valid associated endpoint handle index range.
    158   uint32_t associated_endpoint_handle_begin_;
    159   uint32_t associated_endpoint_handle_end_;
    160 
    161   int stack_depth_;
    162 
    163   DISALLOW_COPY_AND_ASSIGN(ValidationContext);
    164 };
    165 
    166 }  // namespace internal
    167 }  // namespace mojo
    168 
    169 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_CONTEXT_H_
    170