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/validation_context.h"
8#include "mojo/public/cpp/bindings/lib/validation_errors.h"
9#include "mojo/public/cpp/bindings/lib/validation_util.h"
10
11namespace mojo {
12namespace {
13
14bool IsValidMessageHeader(const internal::MessageHeader* header,
15                          internal::ValidationContext* validation_context) {
16  // NOTE: Our goal is to preserve support for future extension of the message
17  // header. If we encounter fields we do not understand, we must ignore them.
18
19  // Extra validation of the struct header:
20  if (header->version == 0) {
21    if (header->num_bytes != sizeof(internal::MessageHeader)) {
22      internal::ReportValidationError(
23          validation_context,
24          internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
25      return false;
26    }
27  } else if (header->version == 1) {
28    if (header->num_bytes != sizeof(internal::MessageHeaderWithRequestID)) {
29      internal::ReportValidationError(
30          validation_context,
31          internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
32      return false;
33    }
34  } else if (header->version > 1) {
35    if (header->num_bytes < sizeof(internal::MessageHeaderWithRequestID)) {
36      internal::ReportValidationError(
37          validation_context,
38          internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
39      return false;
40    }
41  }
42
43  // Validate flags (allow unknown bits):
44
45  // These flags require a RequestID.
46  if (header->version < 1 && ((header->flags & Message::kFlagExpectsResponse) ||
47                              (header->flags & Message::kFlagIsResponse))) {
48    internal::ReportValidationError(
49        validation_context,
50        internal::VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID);
51    return false;
52  }
53
54  // These flags are mutually exclusive.
55  if ((header->flags & Message::kFlagExpectsResponse) &&
56      (header->flags & Message::kFlagIsResponse)) {
57    internal::ReportValidationError(
58        validation_context,
59        internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
60    return false;
61  }
62
63  return true;
64}
65
66}  // namespace
67
68MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink)
69    : MessageHeaderValidator("MessageHeaderValidator", sink) {}
70
71MessageHeaderValidator::MessageHeaderValidator(const std::string& description,
72                                               MessageReceiver* sink)
73    : MessageFilter(sink), description_(description) {
74}
75
76void MessageHeaderValidator::SetDescription(const std::string& description) {
77  description_ = description;
78}
79
80bool MessageHeaderValidator::Accept(Message* message) {
81  // Pass 0 as number of handles because we don't expect any in the header, even
82  // if |message| contains handles.
83  internal::ValidationContext validation_context(
84      message->data(), message->data_num_bytes(), 0, message, description_);
85
86  if (!internal::ValidateStructHeaderAndClaimMemory(message->data(),
87                                                    &validation_context))
88    return false;
89
90  if (!IsValidMessageHeader(message->header(), &validation_context))
91    return false;
92
93  return sink_->Accept(message);
94}
95
96}  // namespace mojo
97