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