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 #include "mojo/public/cpp/bindings/lib/validation_util.h"
6
7 #include <stdint.h>
8
9 #include <limits>
10
11 #include "mojo/public/cpp/bindings/lib/message_internal.h"
12 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
13 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
14 #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
15
16 namespace mojo {
17 namespace internal {
18
ValidateEncodedPointer(const uint64_t * offset)19 bool ValidateEncodedPointer(const uint64_t* offset) {
20 // - Make sure |*offset| is no more than 32-bits.
21 // - Cast |offset| to uintptr_t so overflow behavior is well defined across
22 // 32-bit and 64-bit systems.
23 return *offset <= std::numeric_limits<uint32_t>::max() &&
24 (reinterpret_cast<uintptr_t>(offset) +
25 static_cast<uint32_t>(*offset) >=
26 reinterpret_cast<uintptr_t>(offset));
27 }
28
ValidateStructHeaderAndClaimMemory(const void * data,ValidationContext * validation_context)29 bool ValidateStructHeaderAndClaimMemory(const void* data,
30 ValidationContext* validation_context) {
31 if (!IsAligned(data)) {
32 ReportValidationError(validation_context,
33 VALIDATION_ERROR_MISALIGNED_OBJECT);
34 return false;
35 }
36 if (!validation_context->IsValidRange(data, sizeof(StructHeader))) {
37 ReportValidationError(validation_context,
38 VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
39 return false;
40 }
41
42 const StructHeader* header = static_cast<const StructHeader*>(data);
43
44 if (header->num_bytes < sizeof(StructHeader)) {
45 ReportValidationError(validation_context,
46 VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
47 return false;
48 }
49
50 if (!validation_context->ClaimMemory(data, header->num_bytes)) {
51 ReportValidationError(validation_context,
52 VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
53 return false;
54 }
55
56 return true;
57 }
58
ValidateUnionHeaderAndClaimMemory(const void * data,bool inlined,ValidationContext * validation_context)59 bool ValidateUnionHeaderAndClaimMemory(const void* data,
60 bool inlined,
61 ValidationContext* validation_context) {
62 if (!IsAligned(data)) {
63 ReportValidationError(validation_context,
64 VALIDATION_ERROR_MISALIGNED_OBJECT);
65 return false;
66 }
67
68 // If the union is inlined in another structure its memory was already
69 // claimed.
70 // This ONLY applies to the union itself, NOT anything which the union points
71 // to.
72 if (!inlined && !validation_context->ClaimMemory(data, kUnionDataSize)) {
73 ReportValidationError(validation_context,
74 VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
75 return false;
76 }
77
78 return true;
79 }
80
ValidateMessageIsRequestWithoutResponse(const Message * message,ValidationContext * validation_context)81 bool ValidateMessageIsRequestWithoutResponse(
82 const Message* message,
83 ValidationContext* validation_context) {
84 if (message->has_flag(Message::kFlagIsResponse) ||
85 message->has_flag(Message::kFlagExpectsResponse)) {
86 ReportValidationError(validation_context,
87 VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
88 return false;
89 }
90 return true;
91 }
92
ValidateMessageIsRequestExpectingResponse(const Message * message,ValidationContext * validation_context)93 bool ValidateMessageIsRequestExpectingResponse(
94 const Message* message,
95 ValidationContext* validation_context) {
96 if (message->has_flag(Message::kFlagIsResponse) ||
97 !message->has_flag(Message::kFlagExpectsResponse)) {
98 ReportValidationError(validation_context,
99 VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
100 return false;
101 }
102 return true;
103 }
104
ValidateMessageIsResponse(const Message * message,ValidationContext * validation_context)105 bool ValidateMessageIsResponse(const Message* message,
106 ValidationContext* validation_context) {
107 if (message->has_flag(Message::kFlagExpectsResponse) ||
108 !message->has_flag(Message::kFlagIsResponse)) {
109 ReportValidationError(validation_context,
110 VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
111 return false;
112 }
113 return true;
114 }
115
ValidateControlRequest(const Message * message,ValidationContext * validation_context)116 bool ValidateControlRequest(const Message* message,
117 ValidationContext* validation_context) {
118 switch (message->header()->name) {
119 case kRunMessageId:
120 return ValidateMessageIsRequestExpectingResponse(message,
121 validation_context) &&
122 ValidateMessagePayload<RunMessageParams_Data>(message,
123 validation_context);
124 case kRunOrClosePipeMessageId:
125 return ValidateMessageIsRequestWithoutResponse(message,
126 validation_context) &&
127 ValidateMessagePayload<RunOrClosePipeMessageParams_Data>(
128 message, validation_context);
129 }
130 return false;
131 }
132
ValidateControlResponse(const Message * message,ValidationContext * validation_context)133 bool ValidateControlResponse(const Message* message,
134 ValidationContext* validation_context) {
135 if (!ValidateMessageIsResponse(message, validation_context))
136 return false;
137 switch (message->header()->name) {
138 case kRunMessageId:
139 return ValidateMessagePayload<RunResponseMessageParams_Data>(
140 message, validation_context);
141 }
142 return false;
143 }
144
IsHandleOrInterfaceValid(const AssociatedInterface_Data & input)145 bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input) {
146 return IsValidInterfaceId(input.interface_id);
147 }
148
IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data & input)149 bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input) {
150 return IsValidInterfaceId(input.interface_id);
151 }
152
IsHandleOrInterfaceValid(const Interface_Data & input)153 bool IsHandleOrInterfaceValid(const Interface_Data& input) {
154 return input.handle.is_valid();
155 }
156
IsHandleOrInterfaceValid(const Handle_Data & input)157 bool IsHandleOrInterfaceValid(const Handle_Data& input) {
158 return input.is_valid();
159 }
160
ValidateHandleOrInterfaceNonNullable(const AssociatedInterface_Data & input,const char * error_message,ValidationContext * validation_context)161 bool ValidateHandleOrInterfaceNonNullable(
162 const AssociatedInterface_Data& input,
163 const char* error_message,
164 ValidationContext* validation_context) {
165 if (IsHandleOrInterfaceValid(input))
166 return true;
167
168 ReportValidationError(validation_context,
169 VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
170 error_message);
171 return false;
172 }
173
ValidateHandleOrInterfaceNonNullable(const AssociatedInterfaceRequest_Data & input,const char * error_message,ValidationContext * validation_context)174 bool ValidateHandleOrInterfaceNonNullable(
175 const AssociatedInterfaceRequest_Data& input,
176 const char* error_message,
177 ValidationContext* validation_context) {
178 if (IsHandleOrInterfaceValid(input))
179 return true;
180
181 ReportValidationError(validation_context,
182 VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
183 error_message);
184 return false;
185 }
186
ValidateHandleOrInterfaceNonNullable(const Interface_Data & input,const char * error_message,ValidationContext * validation_context)187 bool ValidateHandleOrInterfaceNonNullable(
188 const Interface_Data& input,
189 const char* error_message,
190 ValidationContext* validation_context) {
191 if (IsHandleOrInterfaceValid(input))
192 return true;
193
194 ReportValidationError(validation_context,
195 VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
196 error_message);
197 return false;
198 }
199
ValidateHandleOrInterfaceNonNullable(const Handle_Data & input,const char * error_message,ValidationContext * validation_context)200 bool ValidateHandleOrInterfaceNonNullable(
201 const Handle_Data& input,
202 const char* error_message,
203 ValidationContext* validation_context) {
204 if (IsHandleOrInterfaceValid(input))
205 return true;
206
207 ReportValidationError(validation_context,
208 VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
209 error_message);
210 return false;
211 }
212
ValidateHandleOrInterface(const AssociatedInterface_Data & input,ValidationContext * validation_context)213 bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
214 ValidationContext* validation_context) {
215 if (!IsMasterInterfaceId(input.interface_id))
216 return true;
217
218 ReportValidationError(validation_context,
219 VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
220 return false;
221 }
222
ValidateHandleOrInterface(const AssociatedInterfaceRequest_Data & input,ValidationContext * validation_context)223 bool ValidateHandleOrInterface(const AssociatedInterfaceRequest_Data& input,
224 ValidationContext* validation_context) {
225 if (!IsMasterInterfaceId(input.interface_id))
226 return true;
227
228 ReportValidationError(validation_context,
229 VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
230 return false;
231 }
232
ValidateHandleOrInterface(const Interface_Data & input,ValidationContext * validation_context)233 bool ValidateHandleOrInterface(const Interface_Data& input,
234 ValidationContext* validation_context) {
235 if (validation_context->ClaimHandle(input.handle))
236 return true;
237
238 ReportValidationError(validation_context, VALIDATION_ERROR_ILLEGAL_HANDLE);
239 return false;
240 }
241
ValidateHandleOrInterface(const Handle_Data & input,ValidationContext * validation_context)242 bool ValidateHandleOrInterface(const Handle_Data& input,
243 ValidationContext* validation_context) {
244 if (validation_context->ClaimHandle(input))
245 return true;
246
247 ReportValidationError(validation_context, VALIDATION_ERROR_ILLEGAL_HANDLE);
248 return false;
249 }
250
251 } // namespace internal
252 } // namespace mojo
253