1 // Copyright 2015 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 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_ 7 8 #include <stdint.h> 9 10 #include "mojo/public/cpp/bindings/bindings_export.h" 11 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" 12 #include "mojo/public/cpp/bindings/lib/serialization_util.h" 13 #include "mojo/public/cpp/bindings/lib/validate_params.h" 14 #include "mojo/public/cpp/bindings/lib/validation_context.h" 15 #include "mojo/public/cpp/bindings/lib/validation_errors.h" 16 #include "mojo/public/cpp/bindings/message.h" 17 18 namespace mojo { 19 namespace internal { 20 21 // Checks whether decoding the pointer will overflow and produce a pointer 22 // smaller than |offset|. 23 inline bool ValidateEncodedPointer(const uint64_t* offset) { 24 // - Make sure |*offset| is no more than 32-bits. 25 // - Cast |offset| to uintptr_t so overflow behavior is well defined across 26 // 32-bit and 64-bit systems. 27 return *offset <= std::numeric_limits<uint32_t>::max() && 28 (reinterpret_cast<uintptr_t>(offset) + 29 static_cast<uint32_t>(*offset) >= 30 reinterpret_cast<uintptr_t>(offset)); 31 } 32 33 template <typename T> 34 bool ValidatePointer(const Pointer<T>& input, 35 ValidationContext* validation_context) { 36 bool result = ValidateEncodedPointer(&input.offset); 37 if (!result) 38 ReportValidationError(validation_context, VALIDATION_ERROR_ILLEGAL_POINTER); 39 40 return result; 41 } 42 43 // Validates that |data| contains a valid struct header, in terms of alignment 44 // and size (i.e., the |num_bytes| field of the header is sufficient for storing 45 // the header itself). Besides, it checks that the memory range 46 // [data, data + num_bytes) is not marked as occupied by other objects in 47 // |validation_context|. On success, the memory range is marked as occupied. 48 // Note: Does not verify |version| or that |num_bytes| is correct for the 49 // claimed version. 50 MOJO_CPP_BINDINGS_EXPORT bool ValidateStructHeaderAndClaimMemory( 51 const void* data, 52 ValidationContext* validation_context); 53 54 // Validates that |data| contains a valid union header, in terms of alignment 55 // and size. It checks that the memory range [data, data + kUnionDataSize) is 56 // not marked as occupied by other objects in |validation_context|. On success, 57 // the memory range is marked as occupied. 58 MOJO_CPP_BINDINGS_EXPORT bool ValidateNonInlinedUnionHeaderAndClaimMemory( 59 const void* data, 60 ValidationContext* validation_context); 61 62 // Validates that the message is a request which doesn't expect a response. 63 MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsRequestWithoutResponse( 64 const Message* message, 65 ValidationContext* validation_context); 66 67 // Validates that the message is a request expecting a response. 68 MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsRequestExpectingResponse( 69 const Message* message, 70 ValidationContext* validation_context); 71 72 // Validates that the message is a response. 73 MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsResponse( 74 const Message* message, 75 ValidationContext* validation_context); 76 77 // Validates that the message payload is a valid struct of type ParamsType. 78 template <typename ParamsType> 79 bool ValidateMessagePayload(const Message* message, 80 ValidationContext* validation_context) { 81 return ParamsType::Validate(message->payload(), validation_context); 82 } 83 84 // The following Validate.*NonNullable() functions validate that the given 85 // |input| is not null/invalid. 86 template <typename T> 87 bool ValidatePointerNonNullable(const T& input, 88 const char* error_message, 89 ValidationContext* validation_context) { 90 if (input.offset) 91 return true; 92 93 ReportValidationError(validation_context, 94 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, 95 error_message); 96 return false; 97 } 98 99 template <typename T> 100 bool ValidateInlinedUnionNonNullable(const T& input, 101 const char* error_message, 102 ValidationContext* validation_context) { 103 if (!input.is_null()) 104 return true; 105 106 ReportValidationError(validation_context, 107 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, 108 error_message); 109 return false; 110 } 111 112 MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid( 113 const AssociatedInterface_Data& input); 114 MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid( 115 const AssociatedEndpointHandle_Data& input); 116 MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid( 117 const Interface_Data& input); 118 MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid( 119 const Handle_Data& input); 120 121 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable( 122 const AssociatedInterface_Data& input, 123 const char* error_message, 124 ValidationContext* validation_context); 125 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable( 126 const AssociatedEndpointHandle_Data& input, 127 const char* error_message, 128 ValidationContext* validation_context); 129 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable( 130 const Interface_Data& input, 131 const char* error_message, 132 ValidationContext* validation_context); 133 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable( 134 const Handle_Data& input, 135 const char* error_message, 136 ValidationContext* validation_context); 137 138 template <typename T> 139 bool ValidateContainer(const Pointer<T>& input, 140 ValidationContext* validation_context, 141 const ContainerValidateParams* validate_params) { 142 ValidationContext::ScopedDepthTracker depth_tracker(validation_context); 143 if (validation_context->ExceedsMaxDepth()) { 144 ReportValidationError(validation_context, 145 VALIDATION_ERROR_MAX_RECURSION_DEPTH); 146 return false; 147 } 148 return ValidatePointer(input, validation_context) && 149 T::Validate(input.Get(), validation_context, validate_params); 150 } 151 152 template <typename T> 153 bool ValidateStruct(const Pointer<T>& input, 154 ValidationContext* validation_context) { 155 ValidationContext::ScopedDepthTracker depth_tracker(validation_context); 156 if (validation_context->ExceedsMaxDepth()) { 157 ReportValidationError(validation_context, 158 VALIDATION_ERROR_MAX_RECURSION_DEPTH); 159 return false; 160 } 161 return ValidatePointer(input, validation_context) && 162 T::Validate(input.Get(), validation_context); 163 } 164 165 template <typename T> 166 bool ValidateInlinedUnion(const T& input, 167 ValidationContext* validation_context) { 168 ValidationContext::ScopedDepthTracker depth_tracker(validation_context); 169 if (validation_context->ExceedsMaxDepth()) { 170 ReportValidationError(validation_context, 171 VALIDATION_ERROR_MAX_RECURSION_DEPTH); 172 return false; 173 } 174 return T::Validate(&input, validation_context, true); 175 } 176 177 template <typename T> 178 bool ValidateNonInlinedUnion(const Pointer<T>& input, 179 ValidationContext* validation_context) { 180 ValidationContext::ScopedDepthTracker depth_tracker(validation_context); 181 if (validation_context->ExceedsMaxDepth()) { 182 ReportValidationError(validation_context, 183 VALIDATION_ERROR_MAX_RECURSION_DEPTH); 184 return false; 185 } 186 return ValidatePointer(input, validation_context) && 187 T::Validate(input.Get(), validation_context, false); 188 } 189 190 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface( 191 const AssociatedInterface_Data& input, 192 ValidationContext* validation_context); 193 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface( 194 const AssociatedEndpointHandle_Data& input, 195 ValidationContext* validation_context); 196 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface( 197 const Interface_Data& input, 198 ValidationContext* validation_context); 199 MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface( 200 const Handle_Data& input, 201 ValidationContext* validation_context); 202 203 } // namespace internal 204 } // namespace mojo 205 206 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_ 207