1 // Copyright 2015 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_UTIL_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_
7
8 #include <stdint.h>
9
10 #include "base/component_export.h"
11 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
12 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
13 #include "mojo/public/cpp/bindings/lib/validate_params.h"
14 #include "mojo/public/cpp/bindings/lib/validation_context.h"
15 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
16 #include "mojo/public/cpp/bindings/message.h"
17
18 namespace mojo {
19 namespace internal {
20
21 // Calls ReportValidationError() with a constructed error string.
22 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
23 void ReportNonNullableValidationError(ValidationContext* validation_context,
24 ValidationError error,
25 int field_index);
26
27 // Checks whether decoding the pointer will overflow and produce a pointer
28 // smaller than |offset|.
ValidateEncodedPointer(const uint64_t * offset)29 inline bool ValidateEncodedPointer(const uint64_t* offset) {
30 // - Make sure |*offset| is no more than 32-bits.
31 // - Cast |offset| to uintptr_t so overflow behavior is well defined across
32 // 32-bit and 64-bit systems.
33 return *offset <= std::numeric_limits<uint32_t>::max() &&
34 (reinterpret_cast<uintptr_t>(offset) +
35 static_cast<uint32_t>(*offset) >=
36 reinterpret_cast<uintptr_t>(offset));
37 }
38
39 template <typename T>
ValidatePointer(const Pointer<T> & input,ValidationContext * validation_context)40 bool ValidatePointer(const Pointer<T>& input,
41 ValidationContext* validation_context) {
42 bool result = ValidateEncodedPointer(&input.offset);
43 if (!result)
44 ReportValidationError(validation_context, VALIDATION_ERROR_ILLEGAL_POINTER);
45
46 return result;
47 }
48
49 // Validates that |data| contains a valid struct header, in terms of alignment
50 // and size (i.e., the |num_bytes| field of the header is sufficient for storing
51 // the header itself). Besides, it checks that the memory range
52 // [data, data + num_bytes) is not marked as occupied by other objects in
53 // |validation_context|. On success, the memory range is marked as occupied.
54 // Note: Does not verify |version| or that |num_bytes| is correct for the
55 // claimed version.
56 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
57 bool ValidateStructHeaderAndClaimMemory(const void* data,
58 ValidationContext* validation_context);
59
60 // Validates that |data| contains a valid union header, in terms of alignment
61 // and size. It checks that the memory range [data, data + kUnionDataSize) is
62 // not marked as occupied by other objects in |validation_context|. On success,
63 // the memory range is marked as occupied.
64 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
65 bool ValidateNonInlinedUnionHeaderAndClaimMemory(
66 const void* data,
67 ValidationContext* validation_context);
68
69 // Validates that the message is a request which doesn't expect a response.
70 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
71 bool ValidateMessageIsRequestWithoutResponse(
72 const Message* message,
73 ValidationContext* validation_context);
74
75 // Validates that the message is a request expecting a response.
76 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
77 bool ValidateMessageIsRequestExpectingResponse(
78 const Message* message,
79 ValidationContext* validation_context);
80
81 // Validates that the message is a response.
82 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
83 bool ValidateMessageIsResponse(const Message* message,
84 ValidationContext* validation_context);
85
86 // Validates that the message payload is a valid struct of type ParamsType.
87 template <typename ParamsType>
ValidateMessagePayload(const Message * message,ValidationContext * validation_context)88 bool ValidateMessagePayload(const Message* message,
89 ValidationContext* validation_context) {
90 return ParamsType::Validate(message->payload(), validation_context);
91 }
92
93 // The following Validate.*NonNullable() functions validate that the given
94 // |input| is not null/invalid.
95 template <typename T>
ValidatePointerNonNullable(const T & input,int field_index,ValidationContext * validation_context)96 bool ValidatePointerNonNullable(const T& input,
97 int field_index,
98 ValidationContext* validation_context) {
99 if (input.offset)
100 return true;
101 ReportNonNullableValidationError(validation_context,
102 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
103 field_index);
104 return false;
105 }
106
107 template <typename T>
ValidateInlinedUnionNonNullable(const T & input,int field_index,ValidationContext * validation_context)108 bool ValidateInlinedUnionNonNullable(const T& input,
109 int field_index,
110 ValidationContext* validation_context) {
111 if (!input.is_null())
112 return true;
113 ReportNonNullableValidationError(validation_context,
114 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
115 field_index);
116 return false;
117 }
118
119 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
120 bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input);
121 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
122 bool IsHandleOrInterfaceValid(const AssociatedEndpointHandle_Data& input);
123 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
124 bool IsHandleOrInterfaceValid(const Interface_Data& input);
125 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
126 bool IsHandleOrInterfaceValid(const Handle_Data& input);
127
128 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
129 bool ValidateHandleOrInterfaceNonNullable(
130 const AssociatedInterface_Data& input,
131 int field_index,
132 ValidationContext* validation_context);
133 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
134 bool ValidateHandleOrInterfaceNonNullable(
135 const AssociatedEndpointHandle_Data& input,
136 int field_index,
137 ValidationContext* validation_context);
138 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
139 bool ValidateHandleOrInterfaceNonNullable(
140 const Interface_Data& input,
141 int field_index,
142 ValidationContext* validation_context);
143 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
144 bool ValidateHandleOrInterfaceNonNullable(
145 const Handle_Data& input,
146 int field_index,
147 ValidationContext* validation_context);
148
149 template <typename T>
ValidateContainer(const Pointer<T> & input,ValidationContext * validation_context,const ContainerValidateParams * validate_params)150 bool ValidateContainer(const Pointer<T>& input,
151 ValidationContext* validation_context,
152 const ContainerValidateParams* validate_params) {
153 ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
154 if (validation_context->ExceedsMaxDepth()) {
155 ReportValidationError(validation_context,
156 VALIDATION_ERROR_MAX_RECURSION_DEPTH);
157 return false;
158 }
159 return ValidatePointer(input, validation_context) &&
160 T::Validate(input.Get(), validation_context, validate_params);
161 }
162
163 template <typename T>
ValidateStruct(const Pointer<T> & input,ValidationContext * validation_context)164 bool ValidateStruct(const Pointer<T>& input,
165 ValidationContext* validation_context) {
166 ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
167 if (validation_context->ExceedsMaxDepth()) {
168 ReportValidationError(validation_context,
169 VALIDATION_ERROR_MAX_RECURSION_DEPTH);
170 return false;
171 }
172 return ValidatePointer(input, validation_context) &&
173 T::Validate(input.Get(), validation_context);
174 }
175
176 template <typename T>
ValidateInlinedUnion(const T & input,ValidationContext * validation_context)177 bool ValidateInlinedUnion(const T& input,
178 ValidationContext* validation_context) {
179 ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
180 if (validation_context->ExceedsMaxDepth()) {
181 ReportValidationError(validation_context,
182 VALIDATION_ERROR_MAX_RECURSION_DEPTH);
183 return false;
184 }
185 return T::Validate(&input, validation_context, true);
186 }
187
188 template <typename T>
ValidateNonInlinedUnion(const Pointer<T> & input,ValidationContext * validation_context)189 bool ValidateNonInlinedUnion(const Pointer<T>& input,
190 ValidationContext* validation_context) {
191 ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
192 if (validation_context->ExceedsMaxDepth()) {
193 ReportValidationError(validation_context,
194 VALIDATION_ERROR_MAX_RECURSION_DEPTH);
195 return false;
196 }
197 return ValidatePointer(input, validation_context) &&
198 T::Validate(input.Get(), validation_context, false);
199 }
200
201 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
202 bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
203 ValidationContext* validation_context);
204 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
205 bool ValidateHandleOrInterface(const AssociatedEndpointHandle_Data& input,
206 ValidationContext* validation_context);
207 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
208 bool ValidateHandleOrInterface(const Interface_Data& input,
209 ValidationContext* validation_context);
210 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
211 bool ValidateHandleOrInterface(const Handle_Data& input,
212 ValidationContext* validation_context);
213
214 } // namespace internal
215 } // namespace mojo
216
217 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_
218