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/lib/message_header_validator.h"
6
7#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
8#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
9#include "mojo/public/cpp/bindings/lib/validation_errors.h"
10
11namespace mojo {
12namespace internal {
13namespace {
14
15bool IsValidMessageHeader(const MessageHeader* header) {
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->num_fields == 2) {
21    if (header->num_bytes != sizeof(MessageHeader)) {
22      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
23      return false;
24    }
25  } else if (header->num_fields == 3) {
26    if (header->num_bytes != sizeof(MessageHeaderWithRequestID)) {
27      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
28      return false;
29    }
30  } else if (header->num_fields > 3) {
31    if (header->num_bytes < sizeof(MessageHeaderWithRequestID)) {
32      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
33      return false;
34    }
35  }
36
37  // Validate flags (allow unknown bits):
38
39  // These flags require a RequestID.
40  if (header->num_fields < 3 &&
41        ((header->flags & kMessageExpectsResponse) ||
42         (header->flags & kMessageIsResponse))) {
43    ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID);
44    return false;
45  }
46
47  // These flags are mutually exclusive.
48  if ((header->flags & kMessageExpectsResponse) &&
49      (header->flags & kMessageIsResponse)) {
50    ReportValidationError(
51        VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION);
52    return false;
53  }
54
55  return true;
56}
57
58}  // namespace
59
60MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink)
61    : MessageFilter(sink) {
62}
63
64bool MessageHeaderValidator::Accept(Message* message) {
65  // Pass 0 as number of handles because we don't expect any in the header, even
66  // if |message| contains handles.
67  BoundsChecker bounds_checker(message->data(), message->data_num_bytes(), 0);
68
69  if (!ValidateStructHeader(message->data(), sizeof(MessageHeader), 2,
70                            &bounds_checker)) {
71    return false;
72  }
73
74  if (!IsValidMessageHeader(message->header()))
75    return false;
76
77  return sink_->Accept(message);
78}
79
80}  // namespace internal
81}  // namespace mojo
82