| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/public/cpp/bindings/message_header_validator.h" | 5 #include "mojo/public/cpp/bindings/message_header_validator.h" |
| 6 | 6 |
| 7 #include "mojo/public/cpp/bindings/lib/array_internal.h" |
| 8 #include "mojo/public/cpp/bindings/lib/validate_params.h" |
| 7 #include "mojo/public/cpp/bindings/lib/validation_context.h" | 9 #include "mojo/public/cpp/bindings/lib/validation_context.h" |
| 8 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | 10 #include "mojo/public/cpp/bindings/lib/validation_errors.h" |
| 9 #include "mojo/public/cpp/bindings/lib/validation_util.h" | 11 #include "mojo/public/cpp/bindings/lib/validation_util.h" |
| 10 | 12 |
| 11 namespace mojo { | 13 namespace mojo { |
| 12 namespace { | 14 namespace { |
| 13 | 15 |
| 16 // TODO(yzshen): Define a mojom struct for message header and use the generated |
| 17 // validation and data view code. |
| 14 bool IsValidMessageHeader(const internal::MessageHeader* header, | 18 bool IsValidMessageHeader(const internal::MessageHeader* header, |
| 15 internal::ValidationContext* validation_context) { | 19 internal::ValidationContext* validation_context) { |
| 16 // NOTE: Our goal is to preserve support for future extension of the message | 20 // NOTE: Our goal is to preserve support for future extension of the message |
| 17 // header. If we encounter fields we do not understand, we must ignore them. | 21 // header. If we encounter fields we do not understand, we must ignore them. |
| 18 | 22 |
| 19 // Extra validation of the struct header: | 23 // Extra validation of the struct header: |
| 20 if (header->version == 0) { | 24 do { |
| 21 if (header->num_bytes != sizeof(internal::MessageHeader)) { | 25 if (header->version == 0) { |
| 22 internal::ReportValidationError( | 26 if (header->num_bytes == sizeof(internal::MessageHeader)) |
| 23 validation_context, | 27 break; |
| 24 internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); | 28 } else if (header->version == 1) { |
| 25 return false; | 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; |
| 26 } | 37 } |
| 27 } else if (header->version == 1) { | 38 internal::ReportValidationError( |
| 28 if (header->num_bytes != sizeof(internal::MessageHeaderWithRequestID)) { | 39 validation_context, |
| 29 internal::ReportValidationError( | 40 internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); |
| 30 validation_context, | 41 return false; |
| 31 internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); | 42 } while (false); |
| 32 return false; | |
| 33 } | |
| 34 } else if (header->version > 1) { | |
| 35 if (header->num_bytes < sizeof(internal::MessageHeaderWithRequestID)) { | |
| 36 internal::ReportValidationError( | |
| 37 validation_context, | |
| 38 internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); | |
| 39 return false; | |
| 40 } | |
| 41 } | |
| 42 | 43 |
| 43 // Validate flags (allow unknown bits): | 44 // Validate flags (allow unknown bits): |
| 44 | 45 |
| 45 // These flags require a RequestID. | 46 // These flags require a RequestID. |
| 46 if (header->version < 1 && ((header->flags & Message::kFlagExpectsResponse) || | 47 constexpr uint32_t kRequestIdFlags = |
| 47 (header->flags & Message::kFlagIsResponse))) { | 48 Message::kFlagExpectsResponse | Message::kFlagIsResponse; |
| 49 if (header->version == 0 && (header->flags & kRequestIdFlags)) { |
| 48 internal::ReportValidationError( | 50 internal::ReportValidationError( |
| 49 validation_context, | 51 validation_context, |
| 50 internal::VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID); | 52 internal::VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID); |
| 51 return false; | 53 return false; |
| 52 } | 54 } |
| 53 | 55 |
| 54 // These flags are mutually exclusive. | 56 // These flags are mutually exclusive. |
| 55 if ((header->flags & Message::kFlagExpectsResponse) && | 57 if ((header->flags & kRequestIdFlags) == kRequestIdFlags) { |
| 56 (header->flags & Message::kFlagIsResponse)) { | |
| 57 internal::ReportValidationError( | 58 internal::ReportValidationError( |
| 58 validation_context, | 59 validation_context, |
| 59 internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); | 60 internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); |
| 60 return false; | 61 return false; |
| 61 } | 62 } |
| 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 |
| 63 return true; | 101 return true; |
| 64 } | 102 } |
| 65 | 103 |
| 66 } // namespace | 104 } // namespace |
| 67 | 105 |
| 68 MessageHeaderValidator::MessageHeaderValidator() | 106 MessageHeaderValidator::MessageHeaderValidator() |
| 69 : MessageHeaderValidator("MessageHeaderValidator") {} | 107 : MessageHeaderValidator("MessageHeaderValidator") {} |
| 70 | 108 |
| 71 MessageHeaderValidator::MessageHeaderValidator(const std::string& description) | 109 MessageHeaderValidator::MessageHeaderValidator(const std::string& description) |
| 72 : description_(description) { | 110 : description_(description) { |
| 73 } | 111 } |
| 74 | 112 |
| 75 void MessageHeaderValidator::SetDescription(const std::string& description) { | 113 void MessageHeaderValidator::SetDescription(const std::string& description) { |
| 76 description_ = description; | 114 description_ = description; |
| 77 } | 115 } |
| 78 | 116 |
| 79 bool MessageHeaderValidator::Accept(Message* message) { | 117 bool MessageHeaderValidator::Accept(Message* message) { |
| 80 // Pass 0 as number of handles because we don't expect any in the header, even | 118 // Pass 0 as number of handles and associated endpoint handles because we |
| 81 // if |message| contains handles. | 119 // don't expect any in the header, even if |message| contains handles. |
| 82 internal::ValidationContext validation_context( | 120 internal::ValidationContext validation_context( |
| 83 message->data(), message->data_num_bytes(), 0, message, description_); | 121 message->data(), message->data_num_bytes(), 0, 0, message, description_); |
| 84 | 122 |
| 85 if (!internal::ValidateStructHeaderAndClaimMemory(message->data(), | 123 if (!internal::ValidateStructHeaderAndClaimMemory(message->data(), |
| 86 &validation_context)) | 124 &validation_context)) |
| 87 return false; | 125 return false; |
| 88 | 126 |
| 89 if (!IsValidMessageHeader(message->header(), &validation_context)) | 127 if (!IsValidMessageHeader(message->header(), &validation_context)) |
| 90 return false; | 128 return false; |
| 91 | 129 |
| 92 return true; | 130 return true; |
| 93 } | 131 } |
| 94 | 132 |
| 95 } // namespace mojo | 133 } // namespace mojo |
| OLD | NEW |