|  | // 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; | 
|  | } | 
|  |  | 
|  | }  // 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_END_TESTCASE(message_packet_tests, "message_packet", "MessagePacket tests") |