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 #include "mojo/public/cpp/bindings/message_header_validator.h" 6 7 #include "mojo/public/cpp/bindings/lib/array_internal.h" 8 #include "mojo/public/cpp/bindings/lib/validate_params.h" 9 #include "mojo/public/cpp/bindings/lib/validation_context.h" 10 #include "mojo/public/cpp/bindings/lib/validation_errors.h" 11 #include "mojo/public/cpp/bindings/lib/validation_util.h" 12 13 namespace mojo { 14 namespace { 15 16 // TODO(yzshen): Define a mojom struct for message header and use the generated 17 // validation and data view code. 18 bool IsValidMessageHeader(const internal::MessageHeader* header, 19 internal::ValidationContext* validation_context) { 20 // NOTE: Our goal is to preserve support for future extension of the message 21 // header. If we encounter fields we do not understand, we must ignore them. 22 23 // Extra validation of the struct header: 24 do { 25 if (header->version == 0) { 26 if (header->num_bytes == sizeof(internal::MessageHeader)) 27 break; 28 } else if (header->version == 1) { 29 if (header->num_bytes == sizeof(internal::MessageHeaderV1)) 30 break; 31 } else if (header->version == 2) { 32 if (header->num_bytes == sizeof(internal::MessageHeaderV2)) 33 break; 34 } else if (header->version > 2) { 35 if (header->num_bytes >= sizeof(internal::MessageHeaderV2)) 36 break; 37 } 38 internal::ReportValidationError( 39 validation_context, 40 internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); 41 return false; 42 } while (false); 43 44 // Validate flags (allow unknown bits): 45 46 // These flags require a RequestID. 47 constexpr uint32_t kRequestIdFlags = 48 Message::kFlagExpectsResponse | Message::kFlagIsResponse; 49 if (header->version == 0 && (header->flags & kRequestIdFlags)) { 50 internal::ReportValidationError( 51 validation_context, 52 internal::VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID); 53 return false; 54 } 55 56 // These flags are mutually exclusive. 57 if ((header->flags & kRequestIdFlags) == kRequestIdFlags) { 58 internal::ReportValidationError( 59 validation_context, 60 internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); 61 return false; 62 } 63 64 if (header->version < 2) 65 return true; 66 67 auto* header_v2 = static_cast<const internal::MessageHeaderV2*>(header); 68 // For the payload pointer: 69 // - Check that the pointer can be safely decoded. 70 // - Claim one byte that the pointer points to. It makes sure not only the 71 // address is within the message, but also the address precedes the array 72 // storing interface IDs (which is important for safely calculating the 73 // payload size). 74 // - Validation of the payload contents will be done separately based on the 75 // payload type. 76 if (!internal::ValidatePointerNonNullable(header_v2->payload, 5, 77 validation_context) || 78 !internal::ValidatePointer(header_v2->payload, validation_context) || 79 !validation_context->ClaimMemory(header_v2->payload.Get(), 1)) { 80 return false; 81 } 82 83 const internal::ContainerValidateParams validate_params(0, false, nullptr); 84 if (!internal::ValidateContainer(header_v2->payload_interface_ids, 85 validation_context, &validate_params)) { 86 return false; 87 } 88 89 if (!header_v2->payload_interface_ids.is_null()) { 90 size_t num_ids = header_v2->payload_interface_ids.Get()->size(); 91 const uint32_t* ids = header_v2->payload_interface_ids.Get()->storage(); 92 for (size_t i = 0; i < num_ids; ++i) { 93 if (!IsValidInterfaceId(ids[i]) || IsMasterInterfaceId(ids[i])) { 94 internal::ReportValidationError( 95 validation_context, 96 internal::VALIDATION_ERROR_ILLEGAL_INTERFACE_ID); 97 return false; 98 } 99 } 100 } 101 102 return true; 103 } 104 105 } // namespace 106 107 MessageHeaderValidator::MessageHeaderValidator() 108 : MessageHeaderValidator("MessageHeaderValidator") {} 109 110 MessageHeaderValidator::MessageHeaderValidator(const std::string& description) 111 : description_(description) { 112 } 113 114 void MessageHeaderValidator::SetDescription(const std::string& description) { 115 description_ = description; 116 } 117 118 bool MessageHeaderValidator::Accept(Message* message) { 119 // Don't bother validating unserialized message headers. 120 if (!message->is_serialized()) 121 return true; 122 123 // Pass 0 as number of handles and associated endpoint handles because we 124 // don't expect any in the header, even if |message| contains handles. 125 internal::ValidationContext validation_context( 126 message->data(), message->data_num_bytes(), 0, 0, message, description_); 127 128 if (!internal::ValidateStructHeaderAndClaimMemory(message->data(), 129 &validation_context)) 130 return false; 131 132 if (!IsValidMessageHeader(message->header(), &validation_context)) 133 return false; 134 135 return true; 136 } 137 138 } // namespace mojo 139