blob: 42e1ab8d7dc0a1e7f83b394bce8c4dc862971151 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_FIDL_CPP_FUZZING_DECODER_ENCODER_H_
#define LIB_FIDL_CPP_FUZZING_DECODER_ENCODER_H_
#include <lib/fidl/llcpp/message.h>
#include <stdint.h>
#include <string.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
namespace fidl {
namespace fuzzing {
// DecoderEncoderProgress encodes the progress of attempted `DecoderEncoder` implementations. Order
// matters here, that is, subsequent (larger) enum values imply further progress in a
// `DecoderEncoder`.
enum DecoderEncoderProgress {
// First operation (decode) failed.
NoProgress = 0,
// First attempt to decode succeeded.
FirstDecodeSuccess,
// First attempt to re-encode decoded message succeeded.
FirstEncodeSuccess,
// Additional checks on handle rights triggered by `::fidl::OutgoingToIncomingMessage` succeeded.
FirstEncodeVerified,
// Second attempt to decode (decode what was just encoded and verified) succeeded.
SecondDecodeSuccess,
// Second attempt to encode (encode object resulting from `SecondDecodeSuccess` step) succeeded.
SecondEncodeSuccess,
};
// DecoderEncoderStatus encapsulates data that results from attempting to decode and encode a
// particular a collection of bytes and handles as a particular FIDL type.
struct DecoderEncoderStatus {
DecoderEncoderProgress progress;
zx_status_t status;
// First encoding data, relevant for `progress >= DecoderEncoderProgress::FirstEncodeSuccess`.
std::vector<uint8_t> first_encoded_bytes;
// TODO(fxbug.dev/72895): Add first handles for koid check.
// Second encoding data, relevant for `progress >= DecoderEncoderProgress::SecondEncodeSuccess`.
std::vector<uint8_t> second_encoded_bytes;
// TODO(fxbug.dev/72895): Add second handles for koid check.
};
// An DecoderEncoder is a function that encapsulates the FIDL type-specific logic for attempting to
// decode and (if decode succeeds) re-encode a FIDL message via the interface documented at
// https://fuchsia.dev/fuchsia-src/reference/fidl/bindings/llcpp-bindings#encoding-decoding.
// Note that a function pointer is used instead of `::std::function` to facilitate header-only
// constexpr globals of type `::std::array<DecoderEncoder, n>`.
using DecoderEncoder = DecoderEncoderStatus (*)(uint8_t* bytes, uint32_t num_bytes,
zx_handle_info_t* handles, uint32_t handle_actual);
} // namespace fuzzing
} // namespace fidl
#ifdef __cplusplus
} // extern "C"
#endif
namespace fidl {
namespace fuzzing {
template <typename T>
DecoderEncoderStatus DecoderEncoderImpl(uint8_t* bytes, uint32_t num_bytes,
zx_handle_info_t* handles, uint32_t num_handles) {
DecoderEncoderStatus status = {
.progress = DecoderEncoderProgress::NoProgress,
.status = ZX_OK,
};
typename T::DecodedMessage decoded(bytes, num_bytes, handles, num_handles);
if (decoded.status() != ZX_OK) {
status.status = decoded.status();
return status;
}
status.progress = DecoderEncoderProgress::FirstDecodeSuccess;
T* value = decoded.PrimaryObject();
typename T::OwnedEncodedMessage encoded(value);
if (encoded.status() != ZX_OK) {
status.status = encoded.status();
return status;
}
status.progress = DecoderEncoderProgress::FirstEncodeSuccess;
auto message_bytes = encoded.GetOutgoingMessage().CopyBytes();
status.first_encoded_bytes =
::std::vector<uint8_t>(message_bytes.data(), message_bytes.data() + message_bytes.size());
// TODO(fxbug.dev/72895): Add handles for koid check.
auto conversion = ::fidl::OutgoingToIncomingMessage(encoded.GetOutgoingMessage());
if (conversion.status() != ZX_OK) {
status.status = encoded.status();
return status;
}
status.progress = DecoderEncoderProgress::FirstEncodeVerified;
typename T::DecodedMessage decoded2(conversion.incoming_message());
if (decoded2.status() != ZX_OK) {
status.status = decoded2.status();
return status;
}
status.progress = DecoderEncoderProgress::SecondDecodeSuccess;
T* value2 = decoded2.PrimaryObject();
typename T::OwnedEncodedMessage encoded2(value2);
if (encoded2.status() != ZX_OK) {
status.status = encoded2.status();
return status;
}
status.progress = DecoderEncoderProgress::SecondEncodeSuccess;
auto message_bytes2 = encoded2.GetOutgoingMessage().CopyBytes();
status.second_encoded_bytes =
::std::vector<uint8_t>(message_bytes2.data(), message_bytes2.data() + message_bytes2.size());
// TODO(fxbug.dev/72895): Add handles for koid check.
return status;
}
} // namespace fuzzing
} // namespace fidl
#endif // LIB_FIDL_CPP_FUZZING_DECODER_ENCODER_H_