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.
IsValidMessageHeader(const internal::MessageHeader * header,internal::ValidationContext * validation_context)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
MessageHeaderValidator()106 MessageHeaderValidator::MessageHeaderValidator()
107 : MessageHeaderValidator("MessageHeaderValidator") {}
108
MessageHeaderValidator(const std::string & description)109 MessageHeaderValidator::MessageHeaderValidator(const std::string& description)
110 : description_(description) {
111 }
112
SetDescription(const std::string & description)113 void MessageHeaderValidator::SetDescription(const std::string& description) {
114 description_ = description;
115 }
116
Accept(Message * message)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