// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include <stdint.h>
#include <limits>
#include "base/strings/stringprintf.h"
#include "mojo/public/cpp/bindings/lib/message_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
namespace mojo {
namespace internal {
void ReportNonNullableValidationError(ValidationContext* validation_context,
ValidationError error,
int field_index) {
const char* null_or_invalid =
error == VALIDATION_ERROR_UNEXPECTED_NULL_POINTER ? "null" : "invalid";
std::string error_message =
base::StringPrintf("%s field %d", null_or_invalid, field_index);
ReportValidationError(validation_context, error, error_message.c_str());
}
bool ValidateStructHeaderAndClaimMemory(const void* data,
ValidationContext* validation_context) {
if (!IsAligned(data)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_MISALIGNED_OBJECT);
return false;
}
if (!validation_context->IsValidRange(data, sizeof(StructHeader))) {
ReportValidationError(validation_context,
VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
return false;
}
const StructHeader* header = static_cast<const StructHeader*>(data);
if (header->num_bytes < sizeof(StructHeader)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
return false;
}
if (!validation_context->ClaimMemory(data, header->num_bytes)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
return false;
}
return true;
}
bool ValidateNonInlinedUnionHeaderAndClaimMemory(
const void* data,
ValidationContext* validation_context) {
if (!IsAligned(data)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_MISALIGNED_OBJECT);
return false;
}
if (!validation_context->ClaimMemory(data, kUnionDataSize) ||
*static_cast<const uint32_t*>(data) != kUnionDataSize) {
ReportValidationError(validation_context,
VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
return false;
}
return true;
}
bool ValidateMessageIsRequestWithoutResponse(
const Message* message,
ValidationContext* validation_context) {
if (message->has_flag(Message::kFlagIsResponse) ||
message->has_flag(Message::kFlagExpectsResponse)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
return false;
}
return true;
}
bool ValidateMessageIsRequestExpectingResponse(
const Message* message,
ValidationContext* validation_context) {
if (message->has_flag(Message::kFlagIsResponse) ||
!message->has_flag(Message::kFlagExpectsResponse)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
return false;
}
return true;
}
bool ValidateMessageIsResponse(const Message* message,
ValidationContext* validation_context) {
if (message->has_flag(Message::kFlagExpectsResponse) ||
!message->has_flag(Message::kFlagIsResponse)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
return false;
}
return true;
}
bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input) {
return input.handle.is_valid();
}
bool IsHandleOrInterfaceValid(const AssociatedEndpointHandle_Data& input) {
return input.is_valid();
}
bool IsHandleOrInterfaceValid(const Interface_Data& input) {
return input.handle.is_valid();
}
bool IsHandleOrInterfaceValid(const Handle_Data& input) {
return input.is_valid();
}
bool ValidateHandleOrInterfaceNonNullable(
const AssociatedInterface_Data& input,
int field_index,
ValidationContext* validation_context) {
if (IsHandleOrInterfaceValid(input))
return true;
ReportNonNullableValidationError(
validation_context, VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
field_index);
return false;
}
bool ValidateHandleOrInterfaceNonNullable(
const AssociatedEndpointHandle_Data& input,
int field_index,
ValidationContext* validation_context) {
if (IsHandleOrInterfaceValid(input))
return true;
ReportNonNullableValidationError(
validation_context, VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
field_index);
return false;
}
bool ValidateHandleOrInterfaceNonNullable(
const Interface_Data& input,
int field_index,
ValidationContext* validation_context) {
if (IsHandleOrInterfaceValid(input))
return true;
ReportNonNullableValidationError(validation_context,
VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
field_index);
return false;
}
bool ValidateHandleOrInterfaceNonNullable(
const Handle_Data& input,
int field_index,
ValidationContext* validation_context) {
if (IsHandleOrInterfaceValid(input))
return true;
ReportNonNullableValidationError(validation_context,
VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
field_index);
return false;
}
bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
ValidationContext* validation_context) {
if (validation_context->ClaimAssociatedEndpointHandle(input.handle))
return true;
ReportValidationError(validation_context,
VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
return false;
}
bool ValidateHandleOrInterface(const AssociatedEndpointHandle_Data& input,
ValidationContext* validation_context) {
if (validation_context->ClaimAssociatedEndpointHandle(input))
return true;
ReportValidationError(validation_context,
VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
return false;
}
bool ValidateHandleOrInterface(const Interface_Data& input,
ValidationContext* validation_context) {
if (validation_context->ClaimHandle(input.handle))
return true;
ReportValidationError(validation_context, VALIDATION_ERROR_ILLEGAL_HANDLE);
return false;
}
bool ValidateHandleOrInterface(const Handle_Data& input,
ValidationContext* validation_context) {
if (validation_context->ClaimHandle(input))
return true;
ReportValidationError(validation_context, VALIDATION_ERROR_ILLEGAL_HANDLE);
return false;
}
} // namespace internal
} // namespace mojo