blob: 667d175f07684d9342385dc9bcb7015a80c74422 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/unittest/unittest.h>
#include <lib/unittest/user_memory.h>
#include <lib/user_copy/user_ptr.h>
#include <ktl/unique_ptr.h>
#include "object/message_packet.h"
namespace {
using testing::UserMemory;
// Create a MessagePacket and call CopyDataTo.
static bool create() {
BEGIN_TEST;
constexpr size_t kSize = 62234;
ktl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = mem->user_in<char>();
auto mem_out = mem->user_out<char>();
fbl::AllocChecker ac;
auto buf = ktl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check());
memset(buf.get(), 'A', kSize);
ASSERT_EQ(ZX_OK, mem_out.copy_array_to_user(buf.get(), kSize));
constexpr uint32_t kNumHandles = 64;
MessagePacketPtr mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(mem_in, kSize, kNumHandles, &mp));
ASSERT_EQ(kSize, mp->data_size());
EXPECT_EQ(kNumHandles, mp->num_handles());
EXPECT_NE(0U, mp->get_txid());
auto result_buf = ktl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check());
ASSERT_EQ(ZX_OK, mp->CopyDataTo(mem_out));
ASSERT_EQ(ZX_OK, mem_in.copy_array_from_user(result_buf.get(), kSize));
EXPECT_EQ(0, memcmp(buf.get(), result_buf.get(), kSize));
END_TEST;
}
// Create a MessagePacket via void* and call CopyDataTo.
static bool create_void_star() {
BEGIN_TEST;
constexpr size_t kSize = 4;
ktl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = mem->user_in<char>();
auto mem_out = mem->user_out<char>();
fbl::AllocChecker ac;
auto in_buf = ktl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check());
memset(in_buf.get(), 'B', kSize);
char* in = in_buf.get();
constexpr uint32_t kNumHandles = 0;
MessagePacketPtr mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(in, kSize, kNumHandles, &mp));
ASSERT_EQ(kSize, mp->data_size());
EXPECT_EQ(kNumHandles, mp->num_handles());
EXPECT_NE(0U, mp->get_txid());
auto result_buf = ktl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check());
ASSERT_EQ(ZX_OK, mp->CopyDataTo(mem_out));
ASSERT_EQ(ZX_OK, mem_in.copy_array_from_user(result_buf.get(), kSize));
EXPECT_EQ(0, memcmp(in_buf.get(), result_buf.get(), kSize));
END_TEST;
}
// Create a MessagePacket with zero-length data.
static bool create_zero() {
BEGIN_TEST;
ktl::unique_ptr<UserMemory> mem = UserMemory::Create(1);
auto mem_in = mem->user_in<char>();
auto mem_out = mem->user_out<char>();
MessagePacketPtr mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(mem_in, 0, 0, &mp));
ASSERT_EQ(0U, mp->data_size());
EXPECT_EQ(0U, mp->num_handles());
EXPECT_EQ(0U, mp->get_txid());
ASSERT_EQ(ZX_OK, mp->CopyDataTo(mem_out));
END_TEST;
}
// Attempt to create a MessagePacket with too many handles.
static bool create_too_many_handles() {
BEGIN_TEST;
ktl::unique_ptr<UserMemory> mem = UserMemory::Create(1);
auto mem_in = mem->user_in<char>();
MessagePacketPtr mp;
EXPECT_EQ(ZX_ERR_OUT_OF_RANGE, MessagePacket::Create(mem_in, 1, 65, &mp));
END_TEST;
}
// Attempt to create a MessagePacket from memory that's not part of userspace.
static bool create_bad_mem() {
BEGIN_TEST;
constexpr size_t kSize = 64;
fbl::AllocChecker ac;
auto buf = ktl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check());
memset(buf.get(), 'C', kSize);
auto in = make_user_in_ptr(static_cast<const char*>(buf.get()));
constexpr uint32_t kNumHandles = 0;
MessagePacketPtr mp;
EXPECT_EQ(ZX_ERR_INVALID_ARGS, MessagePacket::Create(in, kSize, kNumHandles, &mp));
END_TEST;
}
// Attempt to copy a MessagePacket to memory that's not part of userspace.
static bool copy_bad_mem() {
BEGIN_TEST;
constexpr size_t kSize = 64;
ktl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = mem->user_in<char>();
auto mem_out = mem->user_out<char>();
fbl::AllocChecker ac;
auto buf = ktl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check());
memset(buf.get(), 'D', kSize);
ASSERT_EQ(ZX_OK, mem_out.copy_array_to_user(buf.get(), kSize));
constexpr uint32_t kNumHandles = 0;
MessagePacketPtr mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(mem_in, kSize, kNumHandles, &mp));
auto out = make_user_out_ptr(buf.get());
ASSERT_EQ(ZX_ERR_INVALID_ARGS, mp->CopyDataTo(out));
END_TEST;
}
// Create a message packet with the specified number of iovec inputs.
template <uint32_t NIovecs, uint32_t NHandles>
static bool create_iovec() {
BEGIN_TEST;
constexpr uint32_t kNumBytes = NIovecs * (NIovecs - 1) / 2;
ktl::unique_ptr<UserMemory> bytes_mem = UserMemory::Create(kNumBytes);
auto bytes_mem_in = bytes_mem->user_in<char>();
auto bytes_mem_out = bytes_mem->user_out<char>();
char bytes[kNumBytes];
for (uint32_t i = 0; i < sizeof(bytes); i++) {
bytes[i] = static_cast<char>(i);
}
ASSERT_EQ(ZX_OK, bytes_mem_out.copy_array_to_user(bytes, kNumBytes));
zx_channel_iovec_t iovecs[NIovecs];
for (uint32_t i = 0; i < NIovecs; i++) {
iovecs[i] = zx_channel_iovec_t{
.buffer = bytes_mem_in.get(),
.capacity = i,
.reserved = 0,
};
bytes_mem_in = bytes_mem_in.byte_offset(i);
}
ktl::unique_ptr<UserMemory> iovec_mem = UserMemory::Create(NIovecs * sizeof(zx_channel_iovec_t));
auto iovec_mem_in = iovec_mem->user_in<zx_channel_iovec_t>();
auto iovec_mem_out = iovec_mem->user_out<zx_channel_iovec_t>();
ASSERT_EQ(ZX_OK, iovec_mem_out.copy_array_to_user(iovecs, NIovecs));
MessagePacketPtr mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(iovec_mem_in, NIovecs, NHandles, &mp));
EXPECT_EQ(NHandles, mp->num_handles());
ktl::unique_ptr<UserMemory> result_mem = UserMemory::Create(kNumBytes);
auto result_mem_in = result_mem->user_in<char>();
auto result_mem_out = result_mem->user_out<char>();
ASSERT_EQ(ZX_OK, mp->CopyDataTo(result_mem_out));
char result[kNumBytes];
ASSERT_EQ(ZX_OK, result_mem_in.copy_array_from_user(result, kNumBytes));
EXPECT_BYTES_EQ(reinterpret_cast<uint8_t*>(bytes), reinterpret_cast<uint8_t*>(result), kNumBytes);
END_TEST;
}
} // namespace
UNITTEST_START_TESTCASE(message_packet_tests)
UNITTEST("create", create)
UNITTEST("create_void_star", create_void_star)
UNITTEST("create_zero", create_zero)
UNITTEST("create_too_many_handles", create_too_many_handles)
UNITTEST("create_bad_mem", create_bad_mem)
UNITTEST("copy_bad_mem", copy_bad_mem)
UNITTEST("create_iovec_bounded", (create_iovec<MessagePacket::kIovecChunkSize, 0>))
UNITTEST("create_iovec_unbounded", (create_iovec<2 * MessagePacket::kIovecChunkSize, 0>))
UNITTEST("create_iovec_bounded_handles", (create_iovec<MessagePacket::kIovecChunkSize, 3>))
UNITTEST("create_iovec_unbounded_handles", (create_iovec<2 * MessagePacket::kIovecChunkSize, 3>))
UNITTEST_END_TESTCASE(message_packet_tests, "message_packet", "MessagePacket tests")