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