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 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 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 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 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 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 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 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 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 145 bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input) { 146 return IsValidInterfaceId(input.interface_id); 147 } 148 149 bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input) { 150 return IsValidInterfaceId(input.interface_id); 151 } 152 153 bool IsHandleOrInterfaceValid(const Interface_Data& input) { 154 return input.handle.is_valid(); 155 } 156 157 bool IsHandleOrInterfaceValid(const Handle_Data& input) { 158 return input.is_valid(); 159 } 160 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 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 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 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 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 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 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 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