• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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