• 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 (!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