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.
COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)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