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 (!header_v2->payload.is_null() && 77 (!internal::ValidatePointer(header_v2->payload, validation_context) || 78 !validation_context->ClaimMemory(header_v2->payload.Get(), 1))) { 79 return false; 80 } 81 82 const internal::ContainerValidateParams validate_params(0, false, nullptr); 83 if (!internal::ValidateContainer(header_v2->payload_interface_ids, 84 validation_context, &validate_params)) { 85 return false; 86 } 87 88 if (!header_v2->payload_interface_ids.is_null()) { 89 size_t num_ids = header_v2->payload_interface_ids.Get()->size(); 90 const uint32_t* ids = header_v2->payload_interface_ids.Get()->storage(); 91 for (size_t i = 0; i < num_ids; ++i) { 92 if (!IsValidInterfaceId(ids[i]) || IsMasterInterfaceId(ids[i])) { 93 internal::ReportValidationError( 94 validation_context, 95 internal::VALIDATION_ERROR_ILLEGAL_INTERFACE_ID); 96 return false; 97 } 98 } 99 } 100 101 return true; 102 } 103 104 } // namespace 105 106 MessageHeaderValidator::MessageHeaderValidator() 107 : MessageHeaderValidator("MessageHeaderValidator") {} 108 109 MessageHeaderValidator::MessageHeaderValidator(const std::string& description) 110 : description_(description) { 111 } 112 113 void MessageHeaderValidator::SetDescription(const std::string& description) { 114 description_ = description; 115 } 116 117 bool MessageHeaderValidator::Accept(Message* message) { 118 // Pass 0 as number of handles and associated endpoint handles because we 119 // don't expect any in the header, even if |message| contains handles. 120 internal::ValidationContext validation_context( 121 message->data(), message->data_num_bytes(), 0, 0, message, description_); 122 123 if (!internal::ValidateStructHeaderAndClaimMemory(message->data(), 124 &validation_context)) 125 return false; 126 127 if (!IsValidMessageHeader(message->header(), &validation_context)) 128 return false; 129 130 return true; 131 } 132 133 } // namespace mojo 134