Home | History | Annotate | Download | only in lib
      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.
     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 
    107 MessageHeaderValidator::MessageHeaderValidator()
    108     : MessageHeaderValidator("MessageHeaderValidator") {}
    109 
    110 MessageHeaderValidator::MessageHeaderValidator(const std::string& description)
    111     : description_(description) {
    112 }
    113 
    114 void MessageHeaderValidator::SetDescription(const std::string& description) {
    115   description_ = description;
    116 }
    117 
    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