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 (!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
MessageHeaderValidator()107 MessageHeaderValidator::MessageHeaderValidator()
108 : MessageHeaderValidator("MessageHeaderValidator") {}
109
MessageHeaderValidator(const std::string & description)110 MessageHeaderValidator::MessageHeaderValidator(const std::string& description)
111 : description_(description) {
112 }
113
SetDescription(const std::string & description)114 void MessageHeaderValidator::SetDescription(const std::string& description) {
115 description_ = description;
116 }
117
Accept(Message * message)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